我有一节课。
Class First {
private Second second;
public First(int num, String str) {
second = new Second(str);
this.num = num;
}
... // some other methods
}
我想为First类的公共方法编写单元测试。我想避免执行第二类的构造函数。
我这样做了:
Second second = Mockito.mock(Second.class);
Mockito.when(new Second(any(String.class))).thenReturn(null);
First first = new First(null, null);
它仍在调用类Second的构造函数。我怎么能避免它?
答案 0 :(得分:60)
您可以使用PowerMockito
Second second = Mockito.mock(Second.class);
whenNew(Second.class).withNoArguments().thenReturn(second);
但重新分解是更好的决定。
答案 1 :(得分:25)
单元测试的问题再次来自使用new
运算符手动创建对象。请考虑传递已创建的Second
:
class First {
private Second second;
public First(int num, Second second) {
this.second = second;
this.num = num;
}
// some other methods...
}
我知道这可能意味着重写你的API,但没有别的办法。此课程也没有任何意义:
Mockito.when(new Second(any(String.class).thenReturn(null)));
首先,Mockito只能模拟方法,而不是构造函数。其次,即使你可以模拟构造函数,你也在嘲笑刚刚创建的对象的构造函数,并且从不真正对该对象做任何事情。
答案 2 :(得分:13)
以下是使用PowerMockito API模拟此功能的代码。
Second mockedSecond = PowerMockito.mock(Second.class);
PowerMockito.whenNew(Second.class).withNoArguments().thenReturn(mockedSecond);
您需要使用Powermockito运行程序,并且需要添加必需的测试类(逗号分隔),这些类需要被powermock API模拟。
@RunWith(PowerMockRunner.class)
@PrepareForTest({First.class,Second.class})
class TestClassName{
// your testing code
}
答案 3 :(得分:4)
我使用过“模式2 - 工厂助手模式”
模式2 - 工厂帮助模式
这种模式不起作用的一种情况是MyClass是最终的。大多数Mockito框架在最终课程中表现不佳;这包括使用spy()。另一种情况是MyClass在某处使用getClass(),并且要求结果值为MyClass。这是行不通的,因为间谍的类实际上是原始类的Mockito生成的子类。
在上述任何一种情况下,您都需要稍微强大的工厂助手模式,如下所示。
public class MyClass{ static class FactoryHelper{ Foo makeFoo( A a, B b, C c ){ return new Foo( a, b, c ); } } //... private FactoryHelper helper; public MyClass( X x, Y y ){ this( x, y, new FactoryHelper()); } MyClass( X x, Y, y, FactoryHelper helper ){ //... this.helper = helper; } //... Foo foo = helper.makeFoo( a, b, c ); }
所以,你有一个特殊的构造函数,仅用于测试,它有一个额外的参数。在创建要测试的对象时,将从测试类中使用它。在测试类中,您可以模拟FactoryHelper类以及要创建的对象。
@Mock private MyClass.FactoryHelper mockFactoryHelper; @Mock private Foo mockFoo; private MyClass toTest;
你可以像这样使用它
toTest = new MyClass( x, y, mockFactoryHelper ); when( mockFactoryHelper.makeFoo( any( A.class ), any( B.class ), any( C.class ))) .thenReturn( mockFoo );
答案 4 :(得分:1)
Mockito现在可以模拟构造函数(从3.5.0版开始)https://javadoc.io/static/org.mockito/mockito-core/3.5.13/org/mockito/Mockito.html#mocked_construction
try (MockedConstruction mocked = mockConstruction(Foo.class)) {
Foo foo = new Foo();
when(foo.method()).thenReturn("bar");
assertEquals("bar", foo.method());
verify(foo).method();
}
答案 5 :(得分:0)
我相信,使用mockito模拟构造函数是不可能的。相反,我建议采用以下方法
Class First {
private Second second;
public First(int num, String str) {
if(second== null){
//when junit runs, you get the mocked object(not null), hence don't
//initialize
second = new Second(str);
}
this.num = num;
}
... // some other methods
}
class TestFirst{
@InjectMock
First first;//inject mock the real testable class
@Mock
Second second
testMethod(){
//now you can play around with any method of the Second class using its
//mocked object(second),like:
when(second.getSomething(String.class)).thenReturn(null);
}
答案 6 :(得分:0)
在测试类的顶部加上这一行
@PrepareForTest({ First.class })