Reputation:
I have a java class that contains some methods concerning the binary search in an array of integers. Now I should make a new class that verifies the correctness of these methods, testing this methods with different arrays and different elements to look for. For now, this new class of tests I've done in a "standard" way but I know that I could use JUnit. I searched on the internet a few easy guide to follow but I did not understand much.
For example, if my class "main" BinarySearch.java is made in this way:
public class BinarySearch {
private BinarySearch() { }
public static int find(int x, int[] a) {
int i = 0;
int inf = 0;
int sup = a.length - 1;
if(sup == -1 || x < a[0] || x > a[sup])
return -1;
while(inf <= sup) {
i = (inf + sup) >>> 1;
if(x < a[i])
sup = i - 1;
else if(x > a[i])
inf = i + 1;
else
return i;
}
return -1;
}
public static boolean isPresent(int x, int[] a) {
int i = 0;
int inf = 0;
int sup = a.length - 1;
if(sup == -1 || x < a[0] || x > a[sup])
return false;
while(inf <= sup) {
i = (inf + sup) >>> 1;
if(x < a[i])
sup = i - 1;
else if (x > a[i])
inf = i + 1;
else
return true;
}
return false;
}
public static void sort(int[] a) {
int b, c;
int temp;
int s = a.length - 1;
for(b = 0; b < s; ++b) {
for(c = 0; c < s; ++c) {
if(a[c] < a[c + 1]) {
temp = a[c];
a[c] = a[c + 1];
a[c + 1] = temp;
}
}
}
}
public static boolean isSorted(int[] a) {
for(int i = 0; i < a.length-1; i++) {
if(a[i] > a[i + 1]) {
return false;
}
}
return true;
}
public static void isort(int a[]) {
for(int i = 1; i < a.length; i++){
int j = i;
int b = a[i];
while(j > 0 && a[j - 1] > b) {
a[j] = a[j - 1];
j--;
}
a[j] = b;
}
}
}
The test class "standard" is:
public class BinarySearchTestSuite {
private BinarySearchTestSuite() {}
static int tot = 0;
static int pass = 0;
static int nonPass = 0;
static int ecc = 0;
public static void main(String[] args) {
int[] a1 = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int[] a2 = {};
int x1 = 5;
int x2 = 0;
int x3 = 10;
System.out.println();
System.out.println("---- Test method find ----");
//Test n.1
try {
tot++;
System.out.print("Test n.1 - Array: [ ");
for(int i = 0; i < a1.length; i++)
System.out.print(a1[i] + " ");
System.out.println("]. Element to find: " + x1 + ".");
if(a1[BinarySearch.find(x1, a1)] == x1) {
System.out.println(x1 + " is in position " + BinarySearch.find(x1, a1) + ".");
System.out.println("Test OK.");
pass++;
}
else if(BinarySearch.find(x1, a1) == -1) {
System.out.println(x1 + " is not present in array");
System.out.println("TTest OK.");
pass++;
}
else {
System.out.println("Test FAIL.");
nonPass++;
}
} catch(Exception eccezione) {
System.out.println("Test FAIL.");
ecc++;
}
System.out.println();
//Test n.2
try {
tot++;
System.out.print("Test n.2 - Array: [ ");
for(int i = 0; i < a1.length; i++)
System.out.print(a1[i] + " ");
System.out.println("]. Element to find: " + x2 + ".");
if(a1[BinarySearch.find(x2, a1)] == x2) {
System.out.println(x2 + " is in position " + BinarySearch.find(x2, a1) + ".");
System.out.println("Test OK.");
pass++;
}
else if(BinarySearch.find(x1, a1) == -1) {
System.out.println(x1 + " is not present in array");
System.out.println("Test OK.");
pass++;
}
else {
System.out.println("Test FAIL.");
nonPass++;
}
} catch(Exception eccezione) {
System.out.println("Test FAIL.");
ecc++;
}
System.out.println();
//RESULT
System.out.println();
System.out.println("Test totali: " + tot);
System.out.println("Test andati a buon fine: " + pass);
System.out.println("Test falliti: " + nonPass);
System.out.println("Test falliti con lancio di una eccezione: " + ecc);
}
}
How do I create a test class with JUnit? I need some simple examples.
I know that in the test class I have to write this code:
private final ByteArrayOutputStream outBuffer = new ByteArrayOutputStream();
private final ByteArrayOutputStream errBuffer = new ByteArrayOutputStream();
@Before
public void setupOutputStreams() {
System.setOut(new PrintStream(outBuffer));
System.setErr(new PrintStream(errBuffer));
}
@After
public void cleanupOutputStreams() {
System.setOut(null);
System.setErr(null);
}
After this code, how I write the code for the individual test? Then I compile and run this file (BinarySearchTest.java) normally? Or there is another way to do that? I'm a bit confused...
Thanks!
Thanks
Upvotes: 1
Views: 384
Reputation: 95614
Writing a unit test is easy in JUnit4: Write some small methods that use your code, and use JUnit assertions to ensure that your code produces the answers you're expecting.
@RunWith(JUnit4.class) // JUnit4.class is a "runner".
public class BinarySearchTest {
// By convention, the test for class Foo is named FooTest. You can name the
// test anything you'd like, though, especially if you split your test for
// Foo into more than one file.
@Test public void isSortedShouldReturnTrueWhenSorted() { // Same with methods.
assertTrue(BinarySearch.isSorted(new int[] { 2, 4, 6 }));
}
@Test public void isSortedShouldReturnFalseWhenUnsorted() {
assertFalse(BinarySearch.isSorted(new int[] { 4, 2, 6 }));
}
@Test public void isSortedShouldReturnTrueWhenEmpty() {
assertTrue(BinarySearch.isSorted(new int[] {}));
}
// Write more tests here!
}
Though many IDEs have built-in ways of running JUnit tests, you can also run tests from the command line. You don't have to write a main
method, or count passed and failed tests, or print error messages; JUnit will handle that on its own. Instead, you run JUnit, you tell it where to find your test case, and JUnit runs it.
java -cp /usr/share/java/junit.jar org.junit.runner.JUnitCore your.package.BinarySearchTest
# ^ classpath includes JUnit ^ you're running JUnitCore ^ on your test class
For each class you have, for every method you annotate with @Test
, JUnit will create a new instance of your test class, run every @Before
-annotated method, run your @Test
-annotated method, and then run every @After
-annotated method. You may not have any methods annotated @Before
or @After
for simple tests, which is just fine.
The organization of your test cases is mostly yours to decide. Some people prefer to write a single test method that has many assertTrue
or assertEquals
statements (etc) while others prefer to write many tiny test cases that each address a different aspect (as I did above). That's up to you, but remember that JUnit will stop testing any given method after the first assertion fails or any exception is thrown, so having many smaller methods may give you a better idea of what exactly is wrong. Along those lines, specific method names are helpful: You'll never call them yourself, and having JUnit report that isSortedShouldReturnFalseWhenUnsorted
is failing may be much easier than tracing why isSortedWorks
might be failing.
assert
keyword. You can also write your own code that throws exceptions on errors.setOut
and setErr
. Though redirecting those will make for cleaner test output when testing modules that write to stdout and stderr, yours doesn't do that by default, and JUnit doesn't mind either way.Upvotes: 1