Javenue logo

Javenue

Программирование на Java

Информационные технологии

JUnit and Test Cases - Unit Testing in Java

[Версия статьи на русском языке доступна здесь.]

Testing is not a very interesting thing sometimes. Not so long ago developers were using standard output or debugger in order to test their Java classes. But there is another way…

In this article you'll find the introduction to the JUnit library. JUnit framework makes the process of test-writing much easier.

To demonstrate the power of JUnit let us create the simple Java class and write several test cases for it. The class named MathFunc has two methods: factorial of non-negative number and sum of two integer numbers. Also, there is a counter of method calls just to make the class more complex. The source code of the class is shown below.

public class MathFunc {
    int calls;

    public int getCalls() {
        return calls;
    }

    public long factorial(int number) {
        calls++;

        if (number < 0)
            throw new IllegalArgumentException();

        long result = 1;
        if (number > 1) {
            for (int i = 1; i <= number; i++)
                result = result * i;
        }

        return result;
    }

    public long plus(int num1, int num2) {
        calls++;
        return num1 + num2;
    }
}

In order to create Unit test cases we need to create the class with some methods. Of course the class could have auxiliary methods. In order for test-runner to distinguish test methods we need to mark them with @Test annotation.

Annotation could have the following parameters:

  • expected - the exception class which is thrown within the method (see example below);
  • timeout - if test runs more that [timeout] milliseconds then stop execution and count it as failed.

If you want to skip the single test then mark it with @Ignore annotation. Alternatively you can just delete the @Test annotation.

Sometimes you need a context for tests execution, initialized instances of other classes, for example. And after test execution you need to free some resources. In that cases you will need @Before and @After annotations. Method annotated with @Before will be run before each single test case, and @After method will be run after each test case.

If you need before/after functionality only once before and after whole Test class - then use @BeforeClass and @AfterClass.

Finally, the source code of the Test class:

public class MathFuncTest {
    private MathFunc math;

    @Before
    public void init() { math = new MathFunc(); }
    @After
    public void tearDown() { math = null; }

    @Test
    public void calls() {
        assertEquals(0, math.getCalls());

        math.factorial(1);
        assertEquals(1, math.getCalls());

        math.factorial(1);
        assertEquals(2, math.getCalls());
    }

    @Test
    public void factorial() {
        assertTrue(math.factorial(0) == 1);
        assertTrue(math.factorial(1) == 1);
        assertTrue(math.factorial(5) == 120);
    }

    @Test(expected = IllegalArgumentException.class)
    public void factorialNegative() {
        math.factorial(-1);
    }

    @Ignore
    @Test
    public void todo() {
        assertTrue(math.plus(1, 1) == 3);
    }
}

Method named calls tests the correctness of invocation counter. Method named factorial tests factorial calculation for several standard input values. factorialNegative() checks that IllegalArgumentException will be thrown for negative input values. Method named todo will be ignored. Try to remove @Ignore annotation and see what will happen.

assertTrue() checks that the expression will be evaluated as true. Some other useful methods:

  • assertEquals - expected and actual results are equals;
  • assertNull - the expression result is null;
  • assertNotNull - the expression result is not null;
  • assertSame - expected and actual results are the same identity.
  • fail - will throw AssertionError when invoked - so put it in branches which must not be executed.

Nowadays, almost all IDEs are able to find and run tests for your Java projects. If you want to run your text from Java code then you could use Runners. There are text runners - junit.textui.TestRunner, graphical runners - junit.swingui.TestRunner, junit.awtui.TestRunner.

The most modern method to programmatically run tests is JUnitCore. Just add the following method to the MathFuncTest class:

    public static void main(String[] args) throws Exception {
        JUnitCore runner = new JUnitCore();
        Result result = runner.run(MathFuncTest.class);
        System.out.println("run tests: " + result.getRunCount());
        System.out.println("failed tests: " + result.getFailureCount());
        System.out.println("ignored tests: " + result.getIgnoreCount());
        System.out.println("success: " + result.wasSuccessful());
    }

And the execution result is:

    run tests: 3
    failed tests: 0
    ignored tests: 1
    success: true

Originally JUnit was much harder to use. One had to extend junit.framework.TestCase class, define the constructor and pass the test name to the parent class. Each test method had to be prefixed with [test]. To initialize and free resources you had to use setUp and tearDown methods correspondingly. Thank God we have JUnit 4 now.

That's all, folks. I do believe JUnit Framework will help you a lot. Comments and questions are appreciated.


Комментариев: 0

  Выйти

  * для публикации комментариев нужно