Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用JMock测试具体的第三方类_Java_Unit Testing_Jmock - Fatal编程技术网

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

Java 使用JMock测试具体的第三方类,java,unit-testing,jmock,Java,Unit Testing,Jmock,我有一个带有转发方法的类foo: void foo( Concrete c, String s ) { c.bar( s ); } 我想测试foo实际上是否转发。不幸的是,Concrete是第三方库中的一个类,是一个具体类型,而不是接口。因此,我必须在JMock中使用ClassImposteriser来模拟具体的,因此在我的测试用例中,我做了以下操作: @Test public final void testFoo() { Mockery context = new JUnit4Mock

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

void foo( Concrete c, String s ) { c.bar( s ); }
我想测试
foo
实际上是否转发。不幸的是,
Concrete
是第三方库中的一个类,是一个具体类型,而不是接口。因此,我必须在JMock中使用
ClassImposteriser
来模拟
具体的
,因此在我的测试用例中,我做了以下操作:

@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
依次调用一个抛出的方法。那个方法是最终的,所以我不能重写它。此外,即使我注释掉了行
newclassundertest.foo(c,s),当JMock设置异常时抛出异常,而不是在调用
foo
时抛出异常

那么,我如何测试
ClassUnderTest.foo
转发到
Concrete.bar
的方法呢

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


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

问题文本中不清楚Concrete.bar()是final还是Concrete.somethingElse()是final并从Concrete.bar()调用

如果Concrete.bar()不是final,请为混凝土创建一个手写的存根,如下所示:

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类的使用。如果你对混凝土的使用很简单,我会考虑在接口()中包装混凝土,这样你就可以更容易地模拟出来。p> 适配器模式解决方案的好处:可能通过在项目使用混凝土后命名接口来澄清行为。更容易测试


适配器模式解决方案的缺点:引入更多的类,但对生产代码可能没有什么好处。我不知道混凝土的作用是什么,在接口中封装混凝土可能不太实际。

如果一个方法是最终的,那么我们对此无能为力。如果这是一个第三方库,那么我们会考虑将它封装在一个单板层中并嘲笑它,然后进行集成测试来测试库。还有其他框架可以模拟锁定代码,但我们不支持它,因为我们认为这不是一个好主意。

有关模拟类以及如何绕过最终限制的信息,请参阅。

使用功能更强大的模拟工具,例如。然后,您的测试可以写成:

@Test
public void testFoo(final Concrete c)
{
  final String s = "xxx";

  new Expectations() {{
    c.bar(s);
  }};

  new ClassUnderTest().foo(c, s);
}

对于JMockit来说,如果
具体
是一个接口、一个最终类、一个抽象类,或者其他什么,则没有区别。此外,不需要使用
@RunWith
、扩展基本测试类或调用任何方法,如
assertessatified()
;这一切都是以透明的方式自动完成的。

您能扩展此链接吗?只需回答一点?我没有标记,因为我看到你仍然是一个活跃的用户,这是一个旧的答案,但一些更多的解释将是有益的。