簡體   English   中英

使用PowerMock時發生意外的方法調用-EasyMock

[英]Unexpected method call while using PowerMock- EasyMock

我的問題似乎是對嘲笑有一些誤解。 測試代碼。

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上對構建調用的這種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點。 這是此文檔的來源

模擬靜態方法

快速總結

  1. 在測試用例的類級別使用@RunWith(PowerMockRunner.class)批注。
  2. 在測試用例的類級別使用@PrepareForTest(ClassThatContainsStaticMethod.class)批注。
  3. 使用PowerMock.mockStatic(ClassThatContainsStaticMethod.class)模擬此類的所有方法。
  4. 使用PowerMock.replay(ClassThatContainsStaticMethod.class)將類更改為重播模式。
  5. 使用PowerMock.verify(ClassThatContainsStaticMethod.class)將類更改為驗證模式。

您還要嘲笑SqlSessionFactoryBuilder的構造函數調用,因此您也需要考慮一些技巧。 這是此文檔

模擬新對象的構造

快速總結

  1. 在測試用例的類級別使用@RunWith(PowerMockRunner.class)批注。
  2. 在測試用例的類級別使用@PrepareForTest(ClassThatCreatesTheNewInstance.class)批注。
  3. 使用PowerMock.createMock(NewInstanceClass.class)創建應構造的類的模擬對象(我們將其稱為模擬對象)。
  4. 使用PowerMock.expectNew(NewInstanceClass.class).andReturn(mockObject)可以期望新構造類型為NewInstanceClass.class的對象,但可以返回模擬對象。
  5. 使用PowerMock.replay(mockObject,NewInstanceClass.class)將模擬對象和類更改為重播模式,或者使用PowerMock.replayAll()方法。
  6. 使用PowerMock.verify(mockObject,NewInstanceClass.class)更改模擬對象和類以驗證模式,或者使用PowerMock.verifyAll()方法。

牢記這些技巧,針對您提供的要測試的方法,我生成了以下測試方法。 該測試通過了。

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

這是代碼覆蓋率和powermock.mockStatic之間的沖突。

代碼覆蓋率工具將$ jacocoInit靜態方法插入所有類以收集代碼覆蓋率。 運行測試用例時,mockStatic模擬$ jacocoInit靜態方法,這將導致預期的靜態方法調用。

您可以通過在靜態方法上創建部分模擬來避免問題,例如PowerMock.mockStaticPartial(TheClass.class,“ theStaticMethod”),以使模擬電力不會觸及$ jacocoInit方法。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM