如何使用PowerMock模拟非静态方法

7

我正在试图模拟测试方法中的内部方法调用

我的类如下所示

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

当我为方法getStudent()编写junit时,PowerMock中是否有一种方法可以模拟该行?

dao.getStudentDetails();

或者在junit执行期间,使App类使用模拟dao对象而不是实际的dao调用连接到DB?
3个回答

13

您可以使用来自PowerMock的whenNew()方法(请参见https://github.com/powermock/powermock/wiki/Mockito#how-to-mock-construction-of-new-objects)。

完整测试用例

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());
    }
}

我为这个测试案例制作了一个简单的学生类:

public class Student {
    private String name;
    public Student() {
        name = "real";
    }
    public String getName() {
        return name;
    }
}

@PrepareForTest(MyDAO.class) 而不是 App - telebog
1
@telebog 错误。从我的答案链接中:请注意,您必须为测试准备创建新实例的类,而不是 MyClass 本身。例如,如果执行 new MyClass() 的类称为 X,则必须执行 @PrepareForTest(X.class) 才能使 whenNew 正常工作: - Matt Lachman

1
为了充分利用模拟框架,必须注入MyDAO对象。您可以使用Spring或Guice等工具,也可以简单地使用工厂模式来提供DAO对象。然后,在单元测试中,您可以使用测试工厂来提供模拟的DAO对象而不是真实的对象。然后,您可以编写以下代码:
Mockito.when(mockDao.getStudentDetails()).thenReturn(someValue);

+1 建议使用注入来处理这个问题。 - RonK

-1
如果您无法访问Mockito,您也可以使用PowerMock来实现相同的目的。例如,您可以执行以下操作:
@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
    }
}

1
如果您能展示createMock在哪里被调用,我会取消踩下去的操作。它是一个静态导入吗?如果是这样,为什么它不与PowerMock相同呢? - Tom Chamberlain

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接