我想在Mockito中嘲笑一个班级。然后它将发出一个.newInstance()调用,该调用将返回一个实际的类实例(并且在我的情况下将返回一个mock)。
如果设置正确,那么我可以这样做:
ArrayList myListMock = mock(ArrayList.class);
when(myVar.newInstance()).thenReturn(myListMock);
我知道我可以设置它以便类ArrayList的新实例将是一个模拟(使用PowerMockito whenNew),只是想知道是否有办法模拟这种类对象所以我不必覆盖实例创建...
下面是我试图模拟的真正的类,我不能改变它由接口定义的结构。我正在寻找的是一种在调用initialize时提供cvs的方法。
public class InputConstraintValidator
implements ConstraintValidator<InputValidation, StringWrapper> {
Class<? extends SafeString> cvs;
public void initialize(InputValidation constraintAnnotation) {
cvs = constraintAnnotation.inputValidator();
}
public boolean isValid(StringWrapper value,
ConstraintValidatorContext context) {
SafeString instance;
try {
instance = cvs.newInstance();
} catch (InstantiationException e) {
return false;
} catch (IllegalAccessException e) {
return false;
}
}
答案 0 :(得分:0)
Mockito专门用于模拟对象的实例。在引擎盖下,mock方法实际上创建了一个代理,它接收对所有非final方法的调用,并根据需要记录和存根这些调用。 使用Mockito替换Class对象本身的函数是没有好办法的。这给你留下了一些选择:
我没有PowerMock的经验,但似乎是designed for mocking static methods。
在依赖注入样式中,将静态工厂方法设置为工厂实例。由于看起来您实际上并未使用ArrayList
,因此请说明您的课程为FooBar
:
class FooBar {
static class Factory {
static FooBar instance;
FooBar getInstance() {
if (instance == null) {
instance = new FooBar();
}
return instance;
}
}
// ...
}
现在,您的类用户可以接收new FooBar.Factory()
参数,该参数以单例样式创建您的真实FooBar(希望better and more threadsafe比我的简单实现),并且您可以使用纯Mockito来模拟Factory。如果这看起来像是很多样板,那是因为它是,但是如果你想切换到像Guice这样的DI解决方案,你可以减少很多。
考虑将字段或方法包设为私有或受保护,并将其记录为visible for testing purposes。然后,您只能在测试代码中插入模拟实例。
public class InputConstraintValidator implements
ConstraintValidator<InputValidation, StringWrapper> {
Class<? extends SafeString> cvs;
public void initialize(InputValidation constraintAnnotation) {
cvs = constraintAnnotation.inputValidator();
}
public boolean isValid(StringWrapper value,
ConstraintValidatorContext context) {
SafeString instance;
try {
instance = getCvsInstance();
} catch (InstantiationException e) {
return false;
} catch (IllegalAccessException e) {
return false;
}
}
@VisibleForTesting protected getCvsInstance()
throws InstantiationException, IllegalAccessException {
return cvs.newInstance();
}
}
public class InputConstaintValidatorTest {
@Test public void testWithMockCvs() {
final SafeString cvs = mock(SafeString.class);
InputConstraintValidator validator = new InputConstraintValidator() {
@Override protected getCvsInstance() {
return cvs;
}
}
// test
}
}
答案 1 :(得分:-1)
我认为你只需要为Class
引入一个额外的模拟:
ArrayList<?> myListMock = mock(ArrayList.class);
Class<ArrayList> clazz = mock(Class.class);
when(clazz.newInstance()).thenReturn(myListMock);
当然诀窍在于确保你的模拟clazz.newInstance()
最终不会被调用,因为由于类型擦除,你无法指定它实际上是Class<ArrayList>
。< / p>
另外,要小心定义自己的模拟作为基本的ArrayList
- 通常我会使用“真实的”并用模拟填充它。