Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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());
like image 844
Rajesh Hatwar Avatar asked Dec 28 '16 04:12

Rajesh Hatwar


People also ask

How do you mock the results of a private method?

For Mockito, there is no direct support to mock private and static methods. In order to test private methods, you will need to refactor the code to change the access to protected (or package) and you will have to avoid static/final methods.

How do you mock the method of the same class?

Mocking is done when you invoke methods of a class that has external communication like database calls or rest calls. Through mocking you can explicitly define the return value of methods without actually executing the steps of the method.

What is stubbing in Mockito?

A stub is a fake class that comes with preprogrammed return values. It's injected into the class under test to give you absolute control over what's being tested as input. A typical stub is a database connection that allows you to mimic any scenario without having a real database.


2 Answers

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.

like image 171
GhostCat Avatar answered Sep 20 '22 11:09

GhostCat


Can you please try this out.

@Before
public void setUp() {
    UserSessionPool mockConnectionPool = Mockito.mock(UserSessionPool.class);
}

@Test
public void testName() throws Exception {
    //given
    PowerMockito.mockStatic(UserSessionPool.class);
    BDDMockito.given(UserSessionPool.getInstance()(...)).willReturn(mockConnectionPool);
    Mockito.when(mockConnectionPool.getSessionUser(Mockito.anylong())).thenReturn(something);


    //then
    PowerMockito.verifyStatic();

}

Hope this helps. Happy coding !

like image 34
Ravindra Ranwala Avatar answered Sep 19 '22 11:09

Ravindra Ranwala