java - 使用 PowerMock- EasyMock 时意外的方法调用

标签 java mocking easymock powermock

我的问题似乎是对模拟的一些误解。测试代码。

public class CallHandler {
    private SqlSessionFactory sessionFactory;
    public CallHandler() {
        String resource = "mybatis/mybatis-config.xml";
        Reader reader;
        try {
            reader = Resources.getResourceAsReader(resource);
            sessionFactory = new SqlSessionFactoryBuilder().build(reader);
        }
        catch (IOException e) {
            e.printStackTrace();
        }
    }

    public String handleRequest(Call call) {
        // Some Implementation
    }
}

测试类

// I have excluded few unnecessary classes from @PrepareForTest for the post.

@RunWith(PowerMockRunner.class)
@PrepareForTest({SqlSessionFactoryBuilder.class, Resources.class, SqlSessionFactory.class, SqlSession.class})
public class TestCase0 extends TestCase{
    private SqlSessionFactory mockedSessionFactory = PowerMock.createMock(SqlSessionFactory.class);
    private SqlSession mockedSession = PowerMock.createMock(SqlSession.class);
    private CallMapper mockedMapper = PowerMock.createMock(CallMapper.class);
    private SqlSessionFactoryBuilder mockedSqlSessionFactoryBuilder= PowerMock.createMock(SqlSessionFactoryBuilder.class);
    // Others

    @Before
    public void setUp() {
    }

    @Test
    public void test0 () throws Exception {
        mockStatic(CallMapper.class);
        mockStatic(SqlSessionFactoryBuilder.class);
        mockStatic(Resources.class);
        expect(Resources.getResourceAsReader("mybatis/mybatis-config.xml")).andReturn(mockedReader);      expectNew(SqlSessionFactoryBuilder.class).andReturn(mockedSqlSessionFactoryBuilder);  expect(mockedSqlSessionFactoryBuilder.build(mockedReader)).andReturn(mockedSessionFactory);
        expect(mockedSessionFactory.openSession()).andReturn(mockedSession);
        // Few more expectations
        replayAll();
        assertThat(RESULT0).isEqualTo((new CallHandler()).handleRequest(call));
        verifyAll();
    }
}

在新的 SqlSessionFactoryBuilder 上调用构建的模拟似乎没有生效,因为原始的 build() 被调用,因此出现错误。堆栈跟踪

java.lang.AssertionError: 
Unexpected method call Reader.close();
at org.easymock.internal.MockInvocationHandler.invoke(MockInvocationHandler.java:44)
at org.powermock.api.easymock.internal.invocationcontrol.EasyMockMethodInvocationControl.invoke(EasyMockMethodInvocationControl.java:91)
at org.powermock.core.MockGateway.doMethodCall(MockGateway.java:105)
at org.powermock.core.MockGateway.methodCall(MockGateway.java:168)
at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:58)
at org.apache.ibatis.session.SqlSessionFactoryBuilder.build(SqlSessionFactoryBuilder.java:38)
at com.kwench.integration.ivr.CallHandler.<init>(CallHandler.java:48)
at in.kwench.integration.ivr.TestCase0.test0(TestCase0.java:131)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:310)
at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:88)
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:96)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.executeTest(PowerMockJUnit44RunnerDelegateImpl.java:294)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTestInSuper(PowerMockJUnit47RunnerDelegateImpl.java:127)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit47RunnerDelegateImpl$PowerMockJUnit47MethodRunner.executeTest(PowerMockJUnit47RunnerDelegateImpl.java:82)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$PowerMockJUnit44MethodRunner.runBeforesThenTestThenAfters(PowerMockJUnit44RunnerDelegateImpl.java:282)
at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:86)
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:49)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.invokeTestMethod(PowerMockJUnit44RunnerDelegateImpl.java:207)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.runMethods(PowerMockJUnit44RunnerDelegateImpl.java:146)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl$1.run(PowerMockJUnit44RunnerDelegateImpl.java:120)
at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:33)
at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:45)
at org.powermock.modules.junit4.internal.impl.PowerMockJUnit44RunnerDelegateImpl.run(PowerMockJUnit44RunnerDelegateImpl.java:118)
at org.powermock.modules.junit4.common.internal.impl.JUnit4TestSuiteChunkerImpl.run(JUnit4TestSuiteChunkerImpl.java:104)
at org.powermock.modules.junit4.common.internal.impl.AbstractCommonPowerMockRunner.run(AbstractCommonPowerMockRunner.java:53)
at org.powermock.modules.junit4.PowerMockRunner.run(PowerMockRunner.java:53)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)

最佳答案

如果没有您正在测试的代码的完整示例和测试类本身,很难说出您的问题可能出现在哪里。

话虽如此,我猜你的问题是你没有用静态方法准备类。这些需要在测试类开始时在 @PrepareForTest 注释中提供。

PowerMock 的文档提供了以下有关模拟静态方法的提示。我猜你错过了第 2 点。Here is the source for this documentation

Mocking static methods

Quick summary

  1. Use the @RunWith(PowerMockRunner.class) annotation at the class-level of the test case.
  2. Use the @PrepareForTest(ClassThatContainsStaticMethod.class) annotation at the class-level of the test case.
  3. Use PowerMock.mockStatic(ClassThatContainsStaticMethod.class) to mock all methods of this class.
  4. Use PowerMock.replay(ClassThatContainsStaticMethod.class) to change the class to replay mode.
  5. Use PowerMock.verify(ClassThatContainsStaticMethod.class) to change the class to verify mode.

您还模拟了 SqlSessionFactoryBuilder 的构造函数调用,因此您也需要考虑这方面的提示。 Here is the documentation for this

Mock construction of new objects

Quick summary

  1. Use the @RunWith(PowerMockRunner.class) annotation at the class-level of the test case.
  2. Use the @PrepareForTest(ClassThatCreatesTheNewInstance.class) annotation at the class-level of the test case.
  3. Use PowerMock.createMock(NewInstanceClass.class) to create a mock object of the class that should be constructed (let's call it mockObject).
  4. Use PowerMock.expectNew(NewInstanceClass.class).andReturn(mockObject) to expect a new construction of an object of type NewInstanceClass.class but instead return the mock object.
  5. Use PowerMock.replay(mockObject, NewInstanceClass.class) to change the mock object and class to replay mode, alternatively use the PowerMock.replayAll() method.
  6. Use PowerMock.verify(mockObject, NewInstanceClass.class) to change the mock object and class to verify mode, alternatively use the PowerMock.verifyAll() method.

考虑到这些提示,我针对您提供的您尝试测试的方法生成了以下测试方法。这个测试顺利通过。

@RunWith(PowerMockRunner.class)
@PrepareForTest({CallHandler.class, SqlSessionFactoryBuilder.class, Resources.class})
public class CallHandlerTest {

    private static final String RESULT0 = "";

    @Test
    public void test0 () throws Exception {
        final Reader mockedReader = EasyMock.createMock(Reader.class);
        final SqlSessionFactoryBuilder mockedSqlSessionFactoryBuilder = EasyMock.createMock(SqlSessionFactoryBuilder.class);
        final SqlSessionFactory mockedSessionFactory = EasyMock.createMock(SqlSessionFactory.class);

        PowerMock.mockStatic(SqlSessionFactoryBuilder.class);
        PowerMock.mockStatic(Resources.class);

        PowerMock.expectNew(SqlSessionFactoryBuilder.class).andReturn(mockedSqlSessionFactoryBuilder);
        EasyMock.expect(Resources.getResourceAsReader("mybatis/mybatis-config.xml")).andReturn(mockedReader);
        EasyMock.expect(mockedSqlSessionFactoryBuilder.build(mockedReader)).andReturn(mockedSessionFactory);

        PowerMock.replayAll();
        assertThat(RESULT0).isEqualTo((new CallHandler()).handleRequest(new Call()));
        PowerMock.verifyAll();
    }
}

关于java - 使用 PowerMock- EasyMock 时意外的方法调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24361495/

相关文章:

java - 参数返回 void 的 EasyMock 方法

java - 如何在 JUnit @Before 方法以及测试方法中使用 EasyMock 对象

Java字节类型很奇怪?

Eclipse 无法找到 JRE

java - 如何在 try-with-resource block 中模拟变量

c# - 为 `private static readonly` 字段创建 stub

java - 是否可以为单元测试目的强制设置一个内部变量?

java - EasyMock 我这样做对吗?

java - 在 Java 的方法和接收器类型中组合使用通配符

java - Spring MVC 输出中的缓存