【问题标题】:How to mock nested methods using PowerMock如何使用 PowerMock 模拟嵌套方法
【发布时间】:2017-12-14 14:03:50
【问题描述】:

假设我有两个班级 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;
   }
}

现在我想模拟具有对 B 类的嵌套方法调用的 methodA。我尝试编写下面的 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 解决嵌套方法调用..?? 提前感谢

【问题讨论】:

  • 什么是嵌套方法
  • 你用的是power mock和easy mock??
  • 现在我想模拟 methodA - 如果 methodA() 被模拟,那么就没有必要模拟 b.methodB()。
  • 可以使用多个测试框架,但简单的 mock 很糟糕。我建议在你的项目中使用 Powermock 和 mockito。使用 powermock 模拟新对象的创建以及模拟静态和最终方法。使用 mockito 处理其他所有内容。

标签: java unit-testing junit4 powermock easymock


【解决方案1】:

这里有几个问题。

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

其次,如前所述,如果您想模拟methodA,据说是作为使用A 的测试的一部分,那么没有理由模拟来自B 的任何东西,因为@ 的结果987654325@ 被模拟,不会调用B

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

鉴于这些,如果您为A 创建一个接口,并存根来自该接口的响应,您的测试会简单得多,并且您不必求助于这些工具。

【讨论】:

  • EasyMock 和 PowerMock 一起使用。这是使用它们的正常方式。那里没有错。
  • 可以一起使用它们并不意味着您应该这样做。
  • 这里是要一起使用的。 PowerMock 不应该单独使用。但是,我建议不要使用 PowerMock,除非在极端情况下。因为要求它意味着糟糕的设计。但是,当然,有时,您会遇到糟糕的设计。一个经过测试的糟糕设计比一个糟糕的设计更好
【解决方案2】:

您可以通过执行以下操作来实现您的目标。注意 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>

【讨论】:

  • 另外,我会使用简单的模拟重新评估。只需在 powermock 中使用 powermockito api
  • 试过你的代码,但我得到“NoClassDefFoundError”。
  • 你能给我堆栈跟踪吗?
  • 抱歉,该代码适用于 powermockito api。您需要为 powermock 添加 easymock api。我会更新答案
【解决方案3】:

如果您想模拟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 是解决方案。

【讨论】:

    【解决方案4】:

    我通过在测试类中添加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);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-02-09
      • 1970-01-01
      • 1970-01-01
      • 2018-10-19
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-11-04
      相关资源
      最近更新 更多