How to stub return value for the private method of same class using mockito

Rajesh Hatwar picture Rajesh Hatwar · Dec 28, 2016 · Viewed 9.2k times · Source

I am working on spring based project and writing unit test case using JUnit + Mockito. I am facing a problem while stubbing boolean value to a private method of same test class (after changing access level to public, still I have failed to stub the boolean value).

Below code snippet shows the simulation of same problem

class ABC {

    public String method1(User userObj){
        String result = "";

        if(!isValidUser(userObj.getSessionID())){
            return "InvalidUser";
        } else {
           // execute some logic
        }

        return result;
    }


    private boolean isValidUser(String sessionId) {
        // Here it calls some other class to validate the user 
        if (sessionId == null || UserSessionPool.getInstance().getSessionUser(sessionId) == null) {
            return false;
        } else {
            return true;
        }
    } 
}

Here, I would like to write a test case for method1(). In class ABC I have a method called isValidUser() which helps to identify the user with in a session by looking into a global session pool which holds all logged-in used details i.e. UserSessionPool.getInstance().getSessionUser(sessionId).

While testing method1(), the moment test controller triggers isValidUser(userObj.getSessionID()) I would like to return true from isValidUser() method, so that I can continue to test rest of the implementation logic.

So far I have tried following ways using spy and mocked object to call the isValidUser() method and try to return true but nothing worked well.

Using PowerMockito

PowerMockito.doNothing().when(spyed_ABC_ClassObject, "isValidUser", true);

or

PowerMockito.doReturn(true).when(cntrl, "isValidUser", Mockito.anyString());

Using Whitebox

Whitebox.invokeMethod(spyed_ABC_ClassObject, "isValidUser", Mockito.anyString());

Using Mockito.when

when(spyed_ABC_ClassObject.isValidUser(Mockito.anyString())).thenReturn(true);

or

Mockito.doNothing().when(spyed_ABC_ClassObject).isValidUser(Mockito.anyString());

Answer

GhostCat picture GhostCat · Dec 28, 2016

The other answer is: fix your design instead of turning to the big PowerMock hammer.

Yes, PowerMock allows you to mock static methods. But you should understand: static is an abnormality in good OO design. You only use it when you have very good reasons. As it leads to tight coupling between your classes, and surprise: it breaks your ability to write reasonable unit tests. Yes, PowerMock works; but sometimes, it does not. When your classes grow, and you do more and more things "statically", because, you know, PowerMock will do the job ... be prepared for bizarre fails at some point, that can take hours to hunt down; without ever finding real bugs in your production code.

So, consider an alternative:

  1. Do not use static method calls. And if there is some static method around that you can't touch; consider building a small interface around that.
  2. Instead: use dependency injection and simply pass objects implementing some interface into your production code. Because you can mock such objects without the need for PowerMock(ito).

In that sense: you simply created hard to test code. Now you intend to fix that using PowerMock. The other way (much more reasonable in my eyes) is to learn how to write testable code in the first place. Here is a good starting point for that.