Java Test Reference

Overview

Codewars 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 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 matcher) Overrides the description when the `matcher` fails
allOf(Matcher... matchers) Evaluates to true only if ALL of the passed in matchers evaluate to true.
anyOf(Matcher... matchers) 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 Codewars 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

Discuss:

Loading comments...