java - 使用 JMock 测试具体的第三方类

标签 java unit-testing jmock

我有一个带有转发方法的类foo:

void foo( Concrete c, String s ) { c.bar( s ); }

我想测试 foo 是否确实转发。对我来说不幸的是,Concrete 是第三方库中的类,是具体类型,而不是接口(interface)。因此,我必须在 JMock 中使用 ClassImposteriser 来模拟 Concrete,所以在我的测试用例中,我这样做:

@Test
public final void testFoo() {
   Mockery context = new JUnit4Mockery() {{
      setImposteriser(ClassImposteriser.INSTANCE);
   }};

  final Concrete c = context.mock(Concrete.class);
  final String s = "xxx" ;

  // expectations
  context.checking(new Expectations() {{

     oneOf (c).bar(s); // exception gets thrown from here
  }});


  new ClassUnderTest.foo( c, s );
  context.assertIsSatisfied();

不幸的是,Concrete.bar 又调用了一个抛出异常的方法。该方法是 final方法,因此我无法覆盖它。此外,即使我注释掉 new ClassUnderTest.foo( c, s ); 行,当 JMock 设置异常时抛出异常,而不是在调用 foo 时抛出异常。

那么我如何测试方法 ClassUnderTest.foo 是否转发到 Concrete.bar

编辑:
是的,酒吧是最终的。

我的解决方案不是一般的解决方案是使用第三方库中的“Tester”类来正确设置Concrete

最佳答案

如果 Concrete.bar() 是最终的,或者 Concrete.somethingElse() 是最终的并从 Concrete.bar() 调用,则问题文本不清楚。

如果 Concrete.bar() 不是最终的,像这样为 Concrete 创建一个手写 stub :

public class ConcreteStub extends Concrete
{
    public int numCallsToBar = 0;
    @Override
    public void bar(String s) { numCallsToBar++; }
}

在你的测试代码中:

ConcreteStub c = new ConcreteStub();
foo(c,"abc");
assertEquals(1,c.numCallsToBar);

如果 Concrete.bar() 是 final,它会更复杂,答案取决于 Concrete 的复杂性和您的项目对 Concrete 类的使用。如果您对 Concrete 的使用足够简单,我会考虑将 Concrete 包装在一个接口(interface) ( Adapter Pattern ) 中,然后您可以更轻松地模拟出来。

Adapter Pattern 解决方案的好处:在您的项目使用 Concrete 之后,可能通过命名接口(interface)来阐明行为。更容易测试。

Adapter Pattern 解决方案的缺点:引入了更多的类,对生产代码可能没有什么好处。我不知道 Concrete 的作用,将 Concrete 包装在接口(interface)中可能不切实际。

关于java - 使用 JMock 测试具体的第三方类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/741186/

相关文章:

JAVA-如何根据空格将字符串拆分为int数组

java - 在没有 Spring 的情况下解决 JAX RS 中的数组序列化

c# - 如何测试不应该执行的代码?

php - Phake框架: how to clone objects on captureAll?

java - 或期待中

java - 你能模拟你正在测试的类中的方法调用吗?

java - 单个线程是否保证执行 Servlet 及其过滤器?

java - 创建java代码提示用户输入密码并只允许尝试3次然后退出程序

ruby-on-rails - Rails 3 的测试框架?