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()
;这一切都是以透明的方式自动完成的。您能扩展此链接吗?只需回答一点?我没有标记,因为我看到你仍然是一个活跃的用户,这是一个旧的答案,但一些更多的解释将是有益的。