gianluca.aguzzi@unibo.it
angelo.filaseta@unibo.it
public class BuggyNumFinder {
int smallest = Integer.MAX_VALUE;
int largest = Integer.MIN_VALUE;
public void find(int[] numbers){
for(int n : numbers){
if(n < smallest) smallest = n;
else if(n > largest) largest = n;
}
}
}
import java.util.Scanner;
public class BuggyNumFinderProgram {
public static void main(String[] args){
// Lettura input dall'utente
Scanner in = new Scanner(System.in);
System.out.print("Quanti numeri? ");
int n = in.nextInt();
int[] array = new int[n];
for(int i=0; i < n; i++) {
System.out.print(i + "-esimo numero: ");
array[i] = in.nextInt();
}
in.close();
// Costruzione della UUT (Unit Under Test)
BuggyNumFinder nf = new BuggyNumFinder();
// Esecuzione della funzionalità
nf.find(array);
// Stampa dei risultati
System.out.println("Smallest: " + nf.smallest);
System.out.println("Largest: " + nf.largest);
}
}
public class BuggyNumFinderProgram2 {
public static void main(String[] args){
// Test case 1: some numbers
BuggyNumFinder numFinder = new BuggyNumFinder();
int[] input1 = new int[]{ 4, 25, 7, 9 };
numFinder.find(input1);
System.out.println("Apply to { 4, 25, 7, 9 } => " +
" - smallest: " + numFinder.smallest +
" - largest: " + numFinder.largest);
// Test case 2: monotonically increasing sequence
int[] input2 = new int[]{ 10, 20, 30 };
numFinder.find(input2);
System.out.println("Apply to { 10, 20, 30 } => " +
" - smallest: " + numFinder.smallest +
" - largest: " + numFinder.largest);
// Test case 3: monotonically decreasing sequence
numFinder = new BuggyNumFinder();
int[] input3 = new int[]{ 4, 3, 2, 1 };
numFinder.find(input3);
System.out.println("Apply to { 4, 3, 2, 1 } => " +
" - smallest: " + numFinder.smallest +
" - largest: " + numFinder.largest);
}
}
public class BuggyNumFinderTest {
public static void main(String[] args){
// Test case 1: some numbers
BuggyNumFinder numFinder = new BuggyNumFinder();
int[] input1 = new int[]{ 4, 25, 7, 9 };
numFinder.find(input1);
if(!(numFinder.smallest == 4 && numFinder.largest == 25)){
System.out.println("Test Case #1 failed");
}
// Test case 2: monotonically increasing sequence
int[] input2 = new int[]{ 10, 20, 30 };
numFinder.find(input2);
if(!(numFinder.smallest == 10 && numFinder.largest == 30)){
System.out.println("Test Case #2 failed");
}
// Test case 3: monotonically decreasing sequence
numFinder = new BuggyNumFinder();
int[] input3 = new int[]{ 4, 3, 2, 1 };
numFinder.find(input3);
if(!(numFinder.smallest == 1 && numFinder.largest == 4)){
System.out.println("Test Case #3 failed");
}
}
}
BuggyNumFinder
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Assertions;
public class BuggyNumFinderJUnitTest {
BuggyNumFinder numFinder;
@BeforeEach
void setup(){
System.out.println("Setup");
numFinder = new BuggyNumFinder();
}
@Test
public void someNumbers() {
int[] input1 = new int[]{ 4, 25, 7, 9 };
numFinder.find(input1);
Assertions.assertEquals(4, numFinder.smallest);
Assertions.assertEquals(25, numFinder.largest);
}
@Test
public void positiveMonotonicallyIncreasingSequence() {
int[] input1 = new int[]{ 10, 20, 30 };
numFinder.find(input1);
Assertions.assertEquals(10, numFinder.smallest);
Assertions.assertEquals(30, numFinder.largest);
}
@Test
public void positiveMonotonicallyDecreasingSequence() {
int[] input1 = new int[]{ 30, 20, 10 };
numFinder.find(input1);
Assertions.assertEquals(10, numFinder.smallest);
Assertions.assertEquals(30, numFinder.largest);
}
}
BuggyNumFinder
org.junit.jupiter.api.*
@Test
denota uno (o più) test case@BeforeEach
viene eseguito prima di ogni test case
org.junit.jupiter.api.Assertions
è una classe che fornisce vari metodi per esprimere asserzioni
Assertions.assertEquals(e, a)
ha successo se l’oggetto atteso e
è uguale all’oggetto attuale a
@Test
e @BeforeEach
sono delle annotazioni@NomeAnnotazione
@SomeAnnotation(field1 = 88, field2 = "someString")
src/main/java/
src/test/java
plugins {
java // JavaPlugin aggiunge un source set "test" e un task "test"
}
repositories {
mavenCentral() // occorre per risolvere le dipendenze di JUnit
}
dependencies {
// Dipendenza per scrivere i test
testImplementation("org.junit.jupiter:junit-jupiter-api:5.9.1")
// Dipendenza per eseguire i test
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.9.1")
}
tasks.test {
useJUnitPlatform() // configura il task "test" per usare la JUnit Platform
testLogging { events("passed", "skipped", "failed") } // per stampare l'esito di ogni test
}
$ ./gradlew test
$ ./gradlew test --tests it.unibo.*.Buggy*Test # filtra i test da eseguire
org.junit.platform:junit-platform-engine:_
org.junit.platform:junit-platform-launcher:_
API usata dai build tool e dagli IDE
org.junit.jupiter:junit-jupiter-api:_
API per scrivere testorg.junit.jupiter:junit-jupiter-engine:_
engine corrispondenteorg.junit.vintage:junit-vintage-engine:_
engine per test JUnit 4SomeClass
, scriveremo un’altra classe SomeClassTest
che conterrà metodi di test per esercitare la funzionalità offerta da SomeClass
String
StringTest
src/test/java/
public class StringTest {
}
String
è la nostra Unit Under Test (UUT)
public class StringTest {
@Test public void checkContainsWithSubstring() {
String s = "hello world";
String substring = "world";
boolean contained = s.contains(substring);
Assertions.assertTrue(contained);
}
@Test public void checkContainsWithNoSubstring() {
String s = "hello world";
String notSubstring = "bar";
boolean contained = s.contains(notSubstring);
Assertions.assertFalse(contained);
}
}
(ISTQB Glossary) Un test case è
@Test
) può esprimere uno o più test case @Test public void checkContains(){
String s = "hello world";
Assertions.assertTrue(s.contains("hello") && !s.contains("bar"));
} // questo metodo di test copre due test case
junit-jupiter-params
)@ParameterizedTest @ValueSource(strings = {"hello", "world", " ", ""})
public void checkContainsParameterized(String substr){
String s = "hello world";
Assertions.assertTrue(s.contains(substr));
}
// Arrange: imposta la UUT (unit under test) e il contesto del test
String s = "hello world";
String substring = "world";
// Act: esercita la funzionalità
boolean contained = s.contains(substring);
// Assert: asserisce l'aspettativa rispetto al risultato effettivo
Assertions.assertTrue(contained);
import static org.junit.jupiter.api.Assertions.*;
public class OnAssertions {
@Test
public void workingWithAssertions() {
assertFalse("hello" == new String("hello"));
assertEquals("hello", new String("hello"));
assertNotSame("hello", new String("hello"));
assertTrue(new int[] { 1, 2, 3 } != new int[] { 1, 2, 3 });
assertNotEquals(new int[] { 1, 2, 3 }, new int[] { 1, 2, 3 });
assertArrayEquals(new int[] { 1, 2, 3 }, new int[] { 1, 2, 3 });
Object o = null;
assertNull(o);
assertNotNull(new int[]{ });
}
}
import static C.m;
consente di importare nello scope il metodo statico m
della classe C
import static C.*;
@BeforeAll
, @AfterAll
: da applicare a un metodo static
; tale metodo verrà eseguito una sola volta prima o dopo l’esecuzione di tutti i test della classe di test@BeforeEach
, @AfterEach
: da applicare a un metodo d’istanza; tale metodo verrà eseguito prima o dopo ogni test caseSi supponga di voler progettare/implementare la funzionalità di un televisore (diciamo, una classe Tv
)
Prima di implementare la classe Tv
, scriviamo un test associato
public class TvTest {
@Test
public void testTurnOnWhenOff() {
Tv tv = new Tv();
Assumptions.assumeTrue(!tv.isOn());
tv.turnOn();
Assertions.assertTrue(tv.isOn());
}
}
Assumptions.assumeTrue(x)
esprime una assunzione sul test, ovvero una precondizione che, se non verificata, farà sì che il test venga saltato (SKIPPED) dall’esecutore dei testAssicuriamoci che tale test compili. Per farlo, dobbiamo inizializzare la classe Tv
public class Tv {
public void turnOn(){ }
public boolean isOn(){ return false; }
}
public class Tv {
boolean on;
public void turnOn(){
this.on = true;
}
public boolean isOn(){
return this.on;
}
}
public class Tv {
boolean on;
public Tv(){
this.on = false;
}
public void turnOn(){
this.on = true;
}
public boolean isOn(){
return this.on;
}
}
public class TvTest {
Tv tv;
@BeforeEach
public void setUp(){ tv = new Tv(); }
@Test
public void testTurnOnWhenOff() {
Assumptions.assumeTrue(!tv.isOn());
tv.turnOn();
Assertions.assertTrue(tv.isOn());
}
}
turnOff()
Channel
e dello switch dei canali switch(Channel)