0

I'm currently using Mockito as testing framework for my java JSP pages. I do not have plenty experience with it. However, there is a problem that I cannot find a solution to.

The problem is, there is an immutable class which I want to test. You only can initialize the attributes by using the constructor. The values can be retrieved by accessors (getters). However, one of the setter method has a method which executes a construct call of another class.

public class MyImmutableClass {
    private final String foo;
    private final String bar;
    private final int jeez;

    public MyImmutableClass(String f, String b, Integer j) {
        this.foo = setFoo(f);
        // same for other fields
    }

    private String setFoo(String newFoo) {
        String retVal = "";
        List<String> identifiers = new MyDataBaseHandler().getListOfIdentifiers(); // construct call
        if (identifiers.contains(newFoo)) {
            // ...
        }
        else {
            // ...
        }
        return retVal;
    }

    public boolean isValid() {
        // returns the correctness of this instance
    }
}

To test this immutable class, I have imported Mockito and tried the following.

@RunWith(MockitoJUnitRunner.class)
public class MyImmutableClassTest {

    @Test
    public void validConstruction() throws Exception {
        MyDataBaseHandler myDB = mock(MyDataBaseHandler.class);
        doReturn(this.getIdentifiers()).when(myDB).getListOfIdentifiers();

        MyImmutableClass m = new MyImmutableClass("foo", "bar", 1);
        assertTrue(m.isValid());
    }
}

The method this.getIdentifiers() is a private method which reproduces the list of strings. (Only 3 elements are put inside that list for the testing sake). It is to ensure that the validation of the identifier does the job correctly.

However, this test fails. The problem is that getListOfIdentifiers() has a private method call IN the method body. THAT throws a NPE. Apparently, it is difficult to "bypass" the construct call made in the getListOfIdentifiers() method. The callToMyPrivateMethod() connects with the database. Since the unit test is run locally, no database connections can be set up. Hence I want to bypass the return value by using Mockito.

public List<String> getListOfIdentifiers() {
    // ...
    callToMyPrivateMethod(); // throws NPE ...
    // ...
    return list;
}

Report of the NPE:

java.lang.NullPointerException
    at package.MyDataBaseHandler.callToMyPrivateMethod(MyDataBaseHandler.java:67)
    at package.MyDataBaseHandler.getListOfIdentifiers(MyDataBaseHandler.java:25)

That line is actually a statement which creates a prepared statement on the database connection (which itself is not null ... keh). That prepared statement throws a NPE. Replacing the mock(...) to spy(new MyDataBase()) ofc does not work because it's a different instance than what's being constructed.

I have tried the @InjectMock thing too, but that didn't help to solve my problem. It could be that I didn't have implemented that inject thing correctly (the doc is not so clear about that).

Is there a way to resolve this problem, so that the call to the getListOfIdentifiers() is being intercepted by the Mockito framework, which then returns to the list that I have created? Or am I staring to a XY problem?

KarelG
  • 5,176
  • 4
  • 33
  • 49
  • Does [this question](https://stackoverflow.com/questions/8799439/testing-private-method-using-mockito) help? Unless you can refactor, it looks like you would have to use PowerMock. – David Rawson Dec 23 '16 at 20:24

1 Answers1

0

You create an instance of new MyDataBaseHandler() in your test method.

new MyDataBaseHandler() is a dependency that your class under test communicates with. You correctly recognized that because you try to mock it.

But by your current implementation you can't.

There are 2 solutions.

  1. use PowerMock(ito) this would enable you to redirect the call to new MyDataBaseHandler() to return a mock of the MyDataBaseHandler class.
    But I personally think using PowerMock is a surrender to bad design.

  2. improve your design. IMHO creating instances of (direct) dependencies within a class violates the single responsibility pattern. The instantiation of dependencies is simply not a responsibility of a class.

    You should create the instance of MyDataBaseHandler outside of MyImmutableClass and inject it into the MyImmutableClass objects, preferably via constructor.

    Then you have an easy job to replace this dependency with the mock you already created.

Timothy Truckle
  • 15,071
  • 2
  • 27
  • 51
  • Ah, i'm familiar with DI. But (I just realized that) `setFoo(...)` isn't being called first while it does in my example. There are other arguments provided to the constructor which is being validated first. If the validator succeeds, `setFoo(...)` is being called. I'm actually limiting the database construct. But heh, I just realized that I could provide a flyweight db handler object that is versatile enough and provide it to the object constructor. I'm going to investigate that when I'm back at work. – KarelG Dec 24 '16 at 10:57