JUNIT testing void methods

JavaJunit

Java Problem Overview


I have a java class full of void methods, and I want to make some unit test to get maximal code coverage.

For example I have this method :

protected static void checkifValidElements(int arg1,  int arg2) {
    method1(arg1);
    method2(arg1);
    method3(arg1, arg2);
    method4(arg1, arg2);
    method5(arg1);
    method6(arg2);
    method7();
}

Its poorly named for a reason because I translated the code for better understanding. Each methods verify if the arguments are valid in some way and are well written.

Example :

private static void method1(arg1) {
    if (arg1.indexOf("$") == -1) {

        //Add an error message 
        ErrorFile.errorMessages.add("There is a dollar sign in the specified parameter");
    }
}

My unit test are covering the small methods fine because I ask them to check if the ErrorFile contains the error message, but I dont see how I can test my method checkIfValidElements, it returns nothing or change nothing. When I run code coverage with Maven, it tells me that the unit test doesent cover this part of my class.

The only way I see is to change this method to return an int or bollean value, like this :

protected static int checkifValidElements(int arg1,  int arg2) {
    method1(arg1);
    method2(arg1);
    method3(arg1, arg2);
    method4(arg1, arg2);
    method5(arg1);
    method6(arg2);
    method7();
    return 0;
}

With this method I am able to do an assert equals, but it seems to me that it is futile to do this. The problem is that I have a couple of class that are designed like this and its lowering my unit test coverage %.

Java Solutions


Solution 1 - Java

> I want to make some unit test to get maximal code coverage

Code coverage should never be the goal of writing unit tests. You should write unit tests to prove that your code is correct, or help you design it better, or help someone else understand what the code is meant to do.

> but I dont see how I can test my method checkIfValidElements, it returns nothing or change nothing.

Well you should probably give a few tests, which between them check that all 7 methods are called appropriately - both with an invalid argument and with a valid argument, checking the results of ErrorFile each time.

For example, suppose someone removed the call to:

method4(arg1, arg2);

... or accidentally changed the argument order:

method4(arg2, arg1);

How would you notice those problems? Go from that, and design tests to prove it.

Solution 2 - Java

If your method has no side effects, and doesn't return anything, then it's not doing anything.

If your method does some computation and returns the result of that computation, you can obviously enough assert that the result returned is correct.

If your code doesn't return anything but does have side effects, you can call the code and then assert that the correct side effects have happened. What the side effects are will determine how you do the checks.

In your example, you are calling static methods from your non-returning functions, which makes it tricky unless you can inspect that the result of all those static methods are correct. A better way - from a testing point of view - is to inject actual objects in that you call methods on. You can then use something like EasyMock or Mockito to create a Mock Object in your unit test, and inject the mock object into the class. The Mock Object then lets you assert that the correct functions were called, with the correct values and in the correct order.

For example:

private ErrorFile errorFile;

public void setErrorFile(ErrorFile errorFile) {
    this.errorFile = errorFile;
}

private void method1(arg1) {
    if (arg1.indexOf("$") == -1) {

        //Add an error message 
        errorFile.addErrorMessage("There is a dollar sign in the specified parameter");
    }
}

Then in your test you can write:

public void testMethod1() {
    ErrorFile errorFile = EasyMock.createMock(ErrorFile.class);
    errorFile.addErrorMessage("There is a dollar sign in the specified parameter");
    EasyMock.expectLastCall(errorFile);
    EasyMock.replay(errorFile);

    ClassToTest classToTest = new ClassToTest();
    classToTest.setErrorFile(errorFile);
    classToTest.method1("a$b");

    EasyMock.verify(errorFile); // This will fail the test if the required addErrorMessage call didn't happen
}

Solution 3 - Java

You can still unit test a void method by asserting that it had the appropriate side effect. In your method1 example, your unit test might look something like:

public void checkIfValidElementsWithDollarSign() {
    checkIfValidElement("$",19);
    assert ErrorFile.errorMessages.contains("There is a dollar sign in the specified parameter");
}

Solution 4 - Java

You can learn something called "mocking". You can use this, for example, to check if:

  • a function was called
  • a function was called x times
  • a function was called at least x times
  • a function was called with a specific set of parameters. In your case, for example, you can use mocking to check that method3 was called once with whatever you pass as arg1 and arg2.

Have a look at these: https://code.google.com/p/mockito/ https://code.google.com/p/powermock/

Solution 5 - Java

I think you should avoid writing side-effecting method. Return true or false from your method and you can check these methods in unit tests.

Solution 6 - Java

If your method is void and you want to check for an exception, you could use expected: https://weblogs.java.net/blog/johnsmart/archive/2009/09/27/testing-exceptions-junit-47

Solution 7 - Java

If it is possible in your case, you could make your methods method1(arg1) ... method7() protected instead of private so they could be accesible from test class within the same package. Then you can simply test all theese methods separately.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionmetraonView Question on Stackoverflow
Solution 1 - JavaJon SkeetView Answer on Stackoverflow
Solution 2 - JavaGrahamView Answer on Stackoverflow
Solution 3 - JavaJeff StoreyView Answer on Stackoverflow
Solution 4 - JavaSerban StoenescuView Answer on Stackoverflow
Solution 5 - JavaGarbageView Answer on Stackoverflow
Solution 6 - JavaAndreas HartmannView Answer on Stackoverflow
Solution 7 - JavamartlinView Answer on Stackoverflow