Java 生成并引用存根对象进行测试,而不需要存根将扩展的类
这可能是一个简单的问题,但我没能缩短它 我正在测试我的一个类,Java 生成并引用存根对象进行测试,而不需要存根将扩展的类,java,unit-testing,junit,stub,Java,Unit Testing,Junit,Stub,这可能是一个简单的问题,但我没能缩短它 我正在测试我的一个类,ClassToTest。在生产环境中,它将对第三方库对象执行操作,例如ThirdPartyClass 我想用一个存根来模拟那个类。(使用所使用的存根定义:存根为测试期间发出的呼叫提供固定应答,通常对测试中编程的内容以外的任何内容都不响应) 问题是: ClassToTest有一个方法setThirdPartyClass(ThirdPartyClass o)。因此,要将存根传递给它,存根必须扩展ThirdPartyClass。这意味着我
ClassToTest
。在生产环境中,它将对第三方库对象执行操作,例如ThirdPartyClass
我想用一个存根来模拟那个类。(使用所使用的存根定义:存根为测试期间发出的呼叫提供固定应答,通常对测试中编程的内容以外的任何内容都不响应)
问题是:
有一个方法ClassToTest
。因此,要将存根传递给它,存根必须扩展setThirdPartyClass(ThirdPartyClass o)
。这意味着我的测试必须使用第三方库,而我的单元测试需要是自包含的ThirdPartyClass
ClassUnderTest
参数签名等等,例如,在以下两种情况之间来回切换:
classToTest.setThirdPartyClass(ThirdPartyClass o){ /*....*/ }
及
好的,通常存根只是扩展它所模仿的类,所以签名不必更改(并用最少的代码重写构造函数等)
这样做的好方法是什么?您的
ThridPartyClass
是否实现了一个接口?如果是这样,您可以将测试中的类更改为使用接口而不是具体类。然后存根就实现了接口
如果没有,则可以使用诸如和之类的模拟库为您模拟该类
例如,使用easymock:
@Test
public void test(){
ThirdPartyClass mock = createMock(ThirdPartyClass.class);
expect(mock.foo().andReturn("bar");
replay(mock);
classToTest.setThirdPartyClass(mock);
//perform your tests on classToTest
}
您的
ThridPartyClass
是否实现了接口?如果是这样,您可以将测试中的类更改为使用接口而不是具体类。然后存根就实现了接口
如果没有,则可以使用诸如和之类的模拟库为您模拟该类
例如,使用easymock:
@Test
public void test(){
ThirdPartyClass mock = createMock(ThirdPartyClass.class);
expect(mock.foo().andReturn("bar");
replay(mock);
classToTest.setThirdPartyClass(mock);
//perform your tests on classToTest
}
可能不是最好的例子,但本质上,使用Mockito来模拟第三方类
YourClass
测试
public class YourClass {
private String aString;
// Method that depends on third party component
public void someMethod(ThirdPartyClass doc) {
aString = doc.someStringValue();
}
public String getValue() {
return aString;
}
}
使用Mockito模拟ThirdPartyClass
并控制返回的值进行测试
public class YourClassTest {
//Class you want to test
private YourClass testee;
@Test
public void testSomeMethod() {
testee = new YourClass();
//
// ThirdPartyClass. When the method someStringValue()
// is called you control the value returned
//
ThirdPartyClass testDoc = mock(ThirdPartyClass.class);
when(testDoc.someStringValue()).thenReturn("aString");
// Call method to test and pass mock as argument
testee.someMethod(testDoc);
// Check state of your object you want to test
assertThat(testee.getValue(), equalTo("aString"));
}
}
可能不是最好的例子,但本质上,使用Mockito来模拟第三方类
YourClass
测试
public class YourClass {
private String aString;
// Method that depends on third party component
public void someMethod(ThirdPartyClass doc) {
aString = doc.someStringValue();
}
public String getValue() {
return aString;
}
}
使用Mockito模拟ThirdPartyClass
并控制返回的值进行测试
public class YourClassTest {
//Class you want to test
private YourClass testee;
@Test
public void testSomeMethod() {
testee = new YourClass();
//
// ThirdPartyClass. When the method someStringValue()
// is called you control the value returned
//
ThirdPartyClass testDoc = mock(ThirdPartyClass.class);
when(testDoc.someStringValue()).thenReturn("aString");
// Call method to test and pass mock as argument
testee.someMethod(testDoc);
// Check state of your object you want to test
assertThat(testee.getValue(), equalTo("aString"));
}
}
如前所述,模拟(stubing)
ThirdPartyClass
的最简单方法是,如果该类实现了一个接口,并且该接口是您的ClassToTest
使用的完整接口。然后您可以编写一个MockThirdParty
类,该类实现ThirdPartyInterface
。但我想你不能那样做
另一个选项是将ThirdPartyClass
隐藏在您编写的ThirdPartyFacade
类后面。在编写时,您可以让it实现您设计的ThirdPartyInterface
。ThirdPartyFacade
类的方法只是委托给ThirdPartyClass
,因此对该类进行相对较少的测试是安全的;它不需要单元测试。更改ClassToTest
,使其使用对ThirdPartyInterface
对象的引用,而不是对ThirdPartyClass
对象的引用
现在可以编写一个用于测试的
MockThirdPartyFacade
类,该类实现第三方接口
,用于测试ClassToTest
。您可以根据测试的需要使这个模拟类变得简单或复杂。不同的测试用例甚至可以使用不同的模拟类;您不需要一个通用的模拟类。模拟(存根)ThirdPartyClass
最简单的方法是,如果该类实现了一个接口,并且该接口是您的ClassToTest
使用的完整接口。然后您可以编写一个MockThirdParty
类,该类实现ThirdPartyInterface
。但我想你不能那样做
另一个选项是将ThirdPartyClass
隐藏在您编写的ThirdPartyFacade
类后面。在编写时,您可以让it实现您设计的ThirdPartyInterface
。ThirdPartyFacade
类的方法只是委托给ThirdPartyClass
,因此对该类进行相对较少的测试是安全的;它不需要单元测试。更改ClassToTest
,使其使用对ThirdPartyInterface
对象的引用,而不是对ThirdPartyClass
对象的引用
现在可以编写一个用于测试的
MockThirdPartyFacade
类,该类实现第三方接口
,用于测试ClassToTest
。您可以根据测试的需要使这个模拟类变得简单或复杂。不同的测试用例甚至可以使用不同的模拟类;您不需要通用的模拟类。谢谢-不幸的是,它没有实现接口;此外,测试将测试被测试对象的结果状态,而不是对象进行的调用-我希望测试独立于代码的实现。好的,mock只能测试对象发出的调用?mock第三方类允许您的对象对该类发出调用,我假设该类协同更改您要测试的对象的状态。如果您对间接输出不感兴趣,则无需验证对mock的调用;此外,测试将测试被测对象的结果状态,而不是调用obj