How to mock non static methods using PowerMock
Asked Answered
C

3

7

I am trying to mock an inner method call of my test method

My class looks like this

public class App {
public Student getStudent() {
    MyDAO dao = new MyDAO();
    return dao.getStudentDetails();//getStudentDetails is a public 
                                  //non-static method in the DAO class
}

When I write the junit for the method getStudent(), is there a way in PowerMock to mock the line

dao.getStudentDetails();

or make the App class use a mock dao object during junit execution instead of the actual dao call which connects to the DB?

Coupling answered 13/1, 2012 at 3:41 Comment(0)
G
13

You can use the whenNew() method from PowerMock (see https://github.com/powermock/powermock/wiki/Mockito#how-to-mock-construction-of-new-objects)

Full Test Case

import org.junit.*;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import static org.junit.Assert.*;

@RunWith(PowerMockRunner.class)
@PrepareForTest(App.class)
public class AppTest {
    @Test
    public void testGetStudent() throws Exception {
        App app = new App();
        MyDAO mockDao = Mockito.mock(MyDAO.class);
        Student mockStudent = Mockito.mock(Student.class);

        PowerMockito.whenNew(MyDAO.class).withNoArguments().thenReturn(mockDao);
        Mockito.when(mockDao.getStudentDetails()).thenReturn(mockStudent);
        Mockito.when(mockStudent.getName()).thenReturn("mock");

        assertEquals("mock", app.getStudent().getName());
    }
}

I manufactured a simple Student class for this test case:

public class Student {
    private String name;
    public Student() {
        name = "real";
    }
    public String getName() {
        return name;
    }
}
Gujarati answered 3/1, 2013 at 13:47 Comment(2)
@PrepareForTest(MyDAO .class) not AppAurist
@Aurist incorrect. From the link in my answer: Note that you must prepare the class creating the new instance of MyClass for test, not the MyClass itself. E.g. if the class doing new MyClass() is called X then you'd have to do @PrepareForTest(X.class) in order for whenNew to work:Gujarati
G
1

In order to get much out of the mocking framework, the MyDAO object has to be injected. You can either use something like Spring our Guice, or simply use a factory pattern to supply you with the DAO object. Then, in your unit test, you have a test factory to supply you with mock DAO objects instead of real ones. Then you can write code such as:

Mockito.when(mockDao.getStudentDetails()).thenReturn(someValue);
Gelsemium answered 13/1, 2012 at 16:45 Comment(1)
+1 for suggesting injection as the proper way for handling thisLasseter
I
-1

If you don't have access to Mockito, you can also use PowerMock to do the same purpose. For example you could do the following:

@RunWith(PowerMockRunner.class)
@PrepareForTest(App.class)
public class AppTest {
    @Test
    public void testGetStudent() throws Exception {
        MyDAO mockDao = createMock(MyDAO.class);
        expect(mockDao.getStudentDetails()).andReturn(new Student());        
        replay(mockDao);        

        PowerMock.expectNew(MyDAO.class).andReturn(mockDao);
        PowerMock.replay(MyDAO.class);         
        // make sure to replay the class you expect to get called

        App app = new App();

        // do whatever tests you need here
    }
}
Indent answered 22/4, 2013 at 17:57 Comment(1)
Will remove the downvote if you show where createMock is calling to. Is it a static import? If so, why is it not the same as PowerMock.?Bucket

© 2022 - 2024 — McMap. All rights reserved.