JUnit is a widely used unit testing framework for the Java programming language. It is a member of the xUnit family of frameworks that support a wide variety of programming languages and is commonly used when practising TDD (test-driven development).
Take a moment, if necessary, to familiarise yourself with the various terms and concepts in the previous paragraph.
Because JUnit is not part of the Java Standard Library, you will need access to
its source to be able to use it. I have placed a public copy of
junit-4.12.jar
and hamcrest-core-1.3.jar
in my
account which you may use (when logged into the Computer Science servers or
workstations). The examples below will give you the details necessary to do
so. If you would like to use JUnit on your own machine, you can download the
necessary files from the junit.org web
site.
Imagine you were going to write a simple class, OddEven
, with
methods to tell you if a value is odd or even. The class will have a single
constructor accepting an integer value and two boolean methods,
odd
and even
that return true
or
false
as appropriate. Following TDD, you would want to:
For this class, I think a minimum of five values should be tested, two positive integers, one even and one odd, two negative integers, one even and one odd, and zero. Here is a table of the test cases:
Constructor Input | Expected Result for even() |
Expected Result for odd() |
---|---|---|
86 | true |
false |
125 | false |
true |
−62 | true |
false |
−3 | false |
true |
0 | true |
false |
Now we write the test cases in Java using JUnit:
OddEvenTests
. Be sure to
read all of the comments as they explain much of the syntax for using JUnit.
Next up, we write our OddEven
class. Note that there is a bug in the solution; don't fix it
until after you see how JUnit reports the failed tests.
To compile and run the tests with JUnit, you must specify where to find the
JAR files
containing the JUnit classes. This is done by modifying the
classpath which
may be done in two ways. The first way is to specify the path by using the
-cp
flag as follows (be sure to include the colon and
period at the end of the -cp
path when
running):
$ javac -cp /home/phatalsk/public/misc/junit-4.12.jar OddEven.java
OddEvenTests.java
$ java -cp /home/phatalsk/public/misc/hamcrest-core-1.3.jar:/home/phatalsk/public/misc/junit-4.12.jar:. org.junit.runner.JUnitCore OddEvenTests
This is rather tedious to type out every time we want to use JUnit. The second
way is to set the CLASSPATH
environment variable. When you do
this, you do not need to include the -cp
flag as shown above.
Setting the CLASSPATH
environment variable varies by operating
system. In Linux, you would do the following:
$ export CLASSPATH="$CLASSPATH:/home/phatalsk/public/misc/hamcrest-core-1.3.jar:/home/phatalsk/public/misc/junit-4.12.jar:."
Be sure to include the period and colon at the beginning of the
path! Note that you would have to do this once every time
you log on. To automate the process, you can add the line above to your
.mybashrc
. See me in lab if you would like help with this.
Assuming you didn't fix the bug in OddEven
, when you finally run
the tests, you probably saw something that looked like:
... There were 2 failures: 1) testOdd_negativeOdd(OddEvenTests) java.lang.AssertionError at org.junit.Assert.fail(Assert.java:86) at org.junit.Assert.assertTrue(Assert.java:41) at org.junit.Assert.assertTrue(Assert.java:52) at OddEvenTests.oddTestNegative2(OddEvenTests.java:55) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ... 2) testEven_negativeOdd(OddEvenTests) java.lang.AssertionError at org.junit.Assert.fail(Assert.java:86) at org.junit.Assert.assertTrue(Assert.java:41) at org.junit.Assert.assertFalse(Assert.java:64) at org.junit.Assert.assertFalse(Assert.java:74) at OddEvenTests.evenTestNegative2(OddEvenTests.java:75) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ... FAILURES!!! Tests run: 10, Failures: 2
The information that spews forth is the stack trace. It is a list of all the
methods that have been called leading up the error. All we really need to get
out of all this is that two tests of the ten failed,
oddTestNegative2
and evenTestNegative2
. See if you
can reason out why, fix the bug, rerun the tests, and get the output to look
like:
JUnit version 4.12 .......... Time: 0.007 OK (10 tests)
You can compile and run multiple JUnit test classes at the same time (for programs comprised of more than one class). To do so, you simply include the names of all the test classes on the command line as follows:
$ java org.junit.runner.JUnitCore <Class1> <Class2> ...
It is important to test methods that throw exceptions to make sure they
actually throw them as expected. The JUnit @Test
annotation has
an optional form that allows you to specify an expected exception. When the
test if run, JUnit reports success if the expected exception is thrown and a
failure otherwise. Don't forget to import the exception class as necessary.
Here is a sample test method for a method that should throw an
IllegalArgumentException
when passed a negative number:
@Test(expected=IllegalArgumentException.class) public void someTest() { // Test setup... SomeClass sc = new SomeClass(); // The test, call the method in a way that should result in the expected // exception sc.someMethod(-8); }
@Before
, @After
,
@BeforeClass
, @AfterClass
) that give you some
order control within an individual test class.
To learn more about JUnit—it has much more functionality than is explored
here—you are strongly encouraged to explore the
JUnit
documentation, especially that of the Assert
class to see
the many useful testing methods. More information is also available at
junit.org.