Transcript JUnit 4
JUnit
4 26-Apr-20
Comparing JUnit 3 to JUnit 4
All the old assertXXX methods are the same Most things are about equally easy JUnit 4 makes it easier to test that exceptions are thrown when they should be JUnit 4 can still run JUnit 3 tests JUnit 4 provides protection against infinite loops JUnit 4 has some additional features
Migrating from JUnit 3
JUnit 4 requires Java 5 or newer Don’t extend junit.framework.TestCase
; just use an ordinary class Import org.junit.* and org.junit.Assert.* Use a
static
import for org.junit.Assert.* Static imports replace inheritance from junit.framework.TestCase
Use annotations instead of special method names: Instead of a setUp method, put @Before before some method Instead of a tearDown method, put @After before some method Instead of beginning test method names with ‘ test ’, put @Test before each test method
Writing a JUnit test class, I
Start by importing the JUnit 4 classes you need import org.junit.*; import static org.junit.Assert.*; Declare your class in the usual way public class MyProgramTest { Declare any variables you are going to use frequently, typically including an instance of the class being tested MyProgram program; int [] array; int solution;
Writing a JUnit test class, II
If you wish, you can declare
one
the class is first loaded method to be executed
just once,
when This is for expensive setup, such as connecting to a database } @BeforeClass public static void setUpClass() throws Exception { // one-time initialization code If you wish, you can declare
one
method to be executed
just once,
cleanup after all the tests have been completed to do } @AfterClass public static void tearDownClass() throws Exception { // one-time cleanup code
Writing a JUnit test class, III
You can define one or more methods to be executed before each test; typically such methods initialize values, so that each test starts with a fresh set } @Before public void setUp() { program = new MyProgram(); array = new int[] { 1, 2, 3, 4, 5 }; You can define one or more methods to be executed after each test; typically such methods release resources, such as files } @After public void tearDown() {
@Before and @After methods
You can have as many @Before and @After methods as you want Be warned: You don’t know in what order they will execute You can inherit @Before and @After methods from a superclass; execution is as follows: Execute the @Before methods in the superclass Execute the @Before methods in this class Execute a @Test method in this class Execute the @After methods in this class Execute the @After methods in the superclass
Writing a JUnit test class, IV
A test method is annotated with @Test , takes no parameters, and returns no result All the usual assertXXX methods can be used } @Test public void sum() { assertEquals(15, program.sum(array)); assertTrue(program.min(array) > 0);
Special features of @Test
You can limit how long a method is allowed to take This is good protection against infinite loops The time limit is specified in milliseconds The test fails if the method takes too long } @Test (timeout=10) public void greatBig() { assertTrue(program.ackerman(5, 5) > 10e12); Some method calls should throw an exception You can specify that a particular exception is expected The test will pass if the expected exception is thrown, and fail otherwise } @Test (expected=IllegalArgumentException.class) public void factorial() { program.factorial(-5);
Parameterized tests
Using @RunWith(value=Parameterized.class) the same tests with multiple datasets
@RunWith(value=Parameterized.class)
public class FactorialTest { private long expected; private int value; and a @Parameters method, you can run
@Parameters
public static Collection data() { return Arrays.asList( new Object[ ][ ] { { 1, 0 }, { 1, 1 }, { 2, 2 }, { 120, 5 } }); } public FactorialTest(long expected, int value) { // constructor this.expected = expected; this.value = value; }
@Test
public void factorial() { assertEquals(expected, new Calculator().factorial(value)); } } Source: http://today.java.net/pub/a/today/2006/12/07/junit-reloaded.html
Ignoring a test
The @Ignore annotation says to not run a test } @Ignore("I don’t want Dave to know this doesn’t work") @Test public void add() { assertEquals(4, program.sum(2, 2)); You shouldn’t use @Ignore without a very good reason!
Test suites
As before, you can define a suite of tests @RunWith(value=Suite.class) @SuiteClasses(value={MyProgramTest.class, AnotherTest.class}) public class AllTests { … }
Other stuff
Failed tests now throw an AssertionError , rather than JUnit 3’s AssertionFailedError There is now a version of assertEquals for arrays of objects: assertEquals(Object[] expected, Object[] actual) Unfortunately, there is still no assertEquals for arrays of primitives JUnit 3 had an assertEquals(
p
,
p
) method for each kind of primitive
p
, but JUnit 4 only has an assertEquals(
object
,
object
) and depends on autoboxing
A gotcha
The following method: long sum(long x, long y) { return x + y; } with the following test: } @Test public void sum() { assertEquals(4, s.sum(2, 2)); gives: expected: <4> but was: <4> This is due to your friend, autoboxing assertEquals Hence, the 4 no longer exists for primitives, only for objects is autoboxed to an Integer , while sum returns a long The error message means: expected int 4, but got long 4 To make this work, change the 4 to a 4L
JUnit 4 in Eclipse and NetBeans
As usual, the easiest way to create a test class is just to let your IDE do it for you Here is the recommended test-driven approach Create a class containing all the “stub” methods you initially think you will need Have the IDE create the test class, with all the test methods Repeat: Write a test Make sure the test fails Write the method being tested Make sure the test now succeeds Note: When you create the test class, NetBeans in particular puts a lot of garbage lines into each test method; you can just delete these and put in your own code