JUnit Testing Framework
Overview
Qualified supports writing test fixtures for Java using JUnit 4.
The notes are adapted from: Unit Testing with JUnit - Tutorial (vogella.com)
Minimal Test Framework:
- Solution Code:
// Make sure your class is public
public class Calculator {
// You can't test private methods, so it's
public Double multiply (Double a, Double b) {
return a * b;
}
}
- Test Fixture:
import org.junit.Test;
import static org.junit.Assert.assertEquals;
public class CalculatorTest {
@Test
public void testAssociativityOfMultiplication() throws Exception {
Calculator calc = new Calculator();
// Try to test for behavior, rather than specific inputs
// Otherwise people may try to cheat, and only program for exercise inputs!
for (int i = 0; i < 100; i++) {
Double a = Math.random();
Double b = Math.random();
Double c = Math.random();
String message = String.format("(%g * %g) * %g == %g * (%g * %g)", a, b, c, a, b, c);
assertEquals(message,
calc.multiply(calc.multiply(a, b), c),
calc.multiply(a, calc.multiply(b, c)),
1E-14);
}
}
}
JUnit code constructs
JUnit annotations
JUnit 4.x uses annotations to mark methods and to configure the test run. The following table gives an overview of the most important available annotations.
Annotation | Description |
---|---|
@Test public void method() | The @Test annotation identifies a method as a test method. |
@Test (expected = Exception.class) | Fails if the method does not throw the named exception. |
@Test(timeout=100) | Fails if the method takes longer than 100 milliseconds. |
@Before public void method() | This method is executed before each test. It is used to prepare the test environment (e.g., read input data, initialize the class). |
@After public void method() | This method is executed after each test. It is used to cleanup the test environment (e.g., delete temporary data, restore defaults). It can also save memory by cleaning up expensive memory structures. |
@BeforeClass public static void method() | This method is executed once, before the start of all tests. It is used to perform time intensive activities, for example, to connect to a database. Methods marked with this annotation need to be defined as static to work with JUnit. |
@AfterClass public static void method() | This method is executed once, after all tests have been finished. It is used to perform clean-up activities, for example, to disconnect from a database. Methods annotated with this annotation need to be defined as static to work with JUnit. |
@Ignore | Ignores the test method. This is useful when the underlying code has been changed and the test case has not yet been adapted. Or if the execution time of this test is too long to be included. |
Source: http://www.vogella.com/tutorials/JUnit/article.html#usingjunit_annotations
Assert Statements
JUnit provides static methods in the Assert
class to test for certain conditions. These assertion methods typically start with assert
and allow you to specify the error message, the expected and the actual result. An assertion method compares the actual value returned by a test to the expected value, and throws an AssertionException
if the comparison test fails.
The following table gives an overview of these methods. Parameters in [] brackets are optional.
Statement | Description |
---|---|
assertEquals([String message], expected, actual, [tolerance]) | Tests that two values are the same. The optional tolerance is the number of decimals which must be the same (if comparing double s or float s). Note: for arrays the reference is checked not the content of the arrays. Use assertArrayEquals . |
assertArrayEquals([String message], expecteds, actuals) | Asserts that two array types are equals. Supported array types are: byte[] , char[] , int[] , long[] , java.lang.Object[] , and short[] |
assertNull([String message], object) | Checks that the object is null. |
assertNotNull([String message], object) | Checks that the object is not null. |
assertThat([String message], T actual, Matcher | Asserts that actual satisfies the condition specified by matcher . |
assertSame([String message], expected, actual) | Checks that both variables refer to the same object. |
assertNotSame([String message], expected, actual) | Checks that both variables refer to different objects. |
fail(String) | Let the method fail. Might be used to check that a certain part of the code is not reached or to have a failing test before the test code is implemented. The String parameter is optional. |
Source: http://www.vogella.com/tutorials/JUnit/article.html#usingjunit_asserts
CoreMatchers DSL
The assertThat
method allows the use of the CoreMatchers
Domain Specific Language (DSL) for specifying tests.
For more notes on this see:
http://junit-team.github.io/junit/javadoc/4.10/org/hamcrest/CoreMatchers.html
Here are some examples:
import static org.hamcrest.CoreMatchers.*;
import static org.junit.Assert.assertThat;
// ...
assertThat("Help! Integers don't work", 0, is(1));
/* Fails with message:
* Help! Integers don't work
* expected: is <1>
* got value: <0>
*/
assertThat("Zero is one", 0, is(not(1))); // passes
Here is a list of the static CoreMatchers methods:
Static Method | Description |
---|---|
is(thing) | Overloaded, swiss-army-knife method. Can check class membership, decorate another matcher, or check for equality. |
equalTo(T expected) | Matches if the actual value is equal to the expected. You can use is(T expected) as shorthand. |
describedAs(String description, Matcher | Overrides the description when the matcher fails |
allOf(Matcher | Evaluates to true only if ALL of the passed in matchers evaluate to true. |
anyOf(Matcher | Evaluates to true if ANY of the passed in matchers evaluate to true. |
anything() | This matcher always evaluates to true |
not(T matcher) | Matches only if the underlying matcher does not. |
Best practices
Writing JUnit tests Qualified is different than other environments. Here are some tips:
- You are encouraged to output what you are testing when you test it. That way, the person doing the exercise has some visibility into what went wrong.
- Make randomized tests; try to test for behavior, rather than specific input/output pairs
- Try to use underscores rather than camel case, as it makes it easier to read the test runner results
- Try not to use the
assertTrue
test assertion, it's almost never informative to the person doing the exercise