如何使用PowerMock模拟嵌套方法

时间:2017-12-14 14:03:50

标签: java unit-testing junit4 powermock easymock

假设我有两个A和B类。

Class A{
  public String methodA(String name) {
    B b = new B();
    b.methodB(name);
  }
}

Class B{
   public String methodB(String name) {
        return name+name;
   }
}

现在我想模拟方法A,它有一个嵌套方法调用类B.我尝试编写下面的TestCase,但得到 methodNotImplementedException

@Test  
public void testCase() {
  A a = new A();
  B b = PowerMock.createPartialMock(B.class, "methodB");
  EasyMock.expect(b.methodB(anyString())).andReturn("HELLO PTR");
  PowerMock.replayAll();
  String result = a.methodA("hello ptr");
  assertEquals(result, "HELLO PTRHELLO PTR");
  PowerMock.verifyAll();
}

任何人都可以告诉如何使用PowerMock解决嵌套方法调用.. ??  Thanx提前

4 个答案:

答案 0 :(得分:2)

这里有几个问题。

首先,不要同时使用两个模拟框架。没有理由期望在一个框架中创建期望,另一个框架会知道它。

其次,如果如上所述,您想要模拟methodA,据说是对使用A的某些内容进行测试的一部分,则没有理由从B模拟任何内容,因为methodA的结果被模拟,并且不会调用B

第三,mock roles, not objects。这意味着,如果对象C接受A,它不应该得到具体的实现,而应该得到它使用的接口。然后在测试中,您模拟该接口,而不是类。

鉴于这些,如果您为A创建一个接口,并从该接口存根响应,那么您的测试将更加简单,您将不必使用这些工具。

答案 1 :(得分:0)

您可以通过执行以下操作来实现目标。注意whenNew调用

@Test  
public void testCase() {
  A a = new A();
  B b = PowerMock.createPartialMock(B.class, "methodB");
  EasyMock.expect(b.methodB(anyString())).andReturn("HELLO PTR");
  PowerMock.expectNew(B.class).andReturn(b);
  PowerMock.replay(B.class);
  String result = a.methodA("hello ptr");
  assertEquals(result, "HELLO PTRHELLO PTR");
  PowerMock.verifyAll();
}

您还需要将@PrepareForTest(B.class)添加到测试类

最后,您需要添加api依赖

<dependency>
    <groupId>org.powermock</groupId>
    <artifactId>powermock-api-easymock</artifactId>
    <version>1.7.3</version>
    <scope>test</scope>
</dependency>

答案 2 :(得分:0)

如果你想模仿methodA那么就没有必要对B课做任何事情。只是做

@Test
public void testCase() {
    A a = mock(A.class);
    expect(a.methodA()).andReturn("HELLO");
    replay(a);
    // use the mock to test something
    String result = a.methodA("hello ptr");
    assertEquals(result, "HELLO");
    verify(a);
}

但看起来你想要测试A和模拟B.这是不同的。首先,我建议重构。即使是非常基本的,如

public class A{
    public String methodA(String name) {
        B b = newB();
        b.methodB(name);
    }

    protected B newB() {
        return new B()
    }
}

这样,你根本不需要PowerMock。你可以做到

@Test
public void testCase() {
    A a = partialMockBuilder().addMockedMethod("newB").mock(A.class);
    B b = mock(B.class);
    expect(a.newB()).andReturn(b);
    expect(b.methodB()).andReturn("HELLO");
    replay(a, b);        

    String result = a.methodA("HI");
    assertEquals(result, "HELLO");

    verify(a, b);
}

然后,如果你真的需要一些奇怪的理由来模仿new B(),是的,使用Powermock.expectNew是解决方案。

答案 3 :(得分:0)

我通过在测试类中添加PowerMock.expectNew(B.class).andReturn(b);@Mock注释来解决此问题。

完整代码;

public class A {
    public String methodA(String name) {
        B b = new B();
        return b.methodB(name);
    }
}

public class B{
    public String methodB(String name) {
        return name+name;
    }
}

@RunWith(PowerMockRunner.class)
@PrepareForTest({ A.class, B.class })
public class TestCase {

    @Mock
    private B b;

    @Test  
    public void testCase() throws Exception {
       A a = new A();
       PowerMock.expectNew(B.class).andReturn(b);
       EasyMock.expect(b.methodB(anyString())).andReturn("HELLO");
       PowerMock.replay(B.class, b);
       String result = a.methodA("HI");
       assertTrue(result != null);
       assertEquals(result, "HELLO");
       PowerMock.verify(B.class, b);
    }
}