在具体 Class Mockito 中模拟链式调用
Mocking Chained calls in Concrete Class Mockito
我正在使用 Mockito 服务来测试可能在 MyFinalClass 中抛出并在 MyAbstractClass 中捕获的异常,因为具体方法调用 MyFinalClass 中的 getObject 方法。
请看下面的代码。
public abstract class MyAbstractClass{
@Autowired
private MyFinalClass myFinalClass;
//concrete method
protected Object myConcreteMethod(String name){
try{
Object b = myFinalClass.getObject(name);
return b;
} catch(MyException e){
LOGGER.log("ERROR THROWN" + e);
}
}
}
public final class MyFinalClass {
public Object getObject(String name) throws MyException{
**** HAS NOT YET BEEN IMPLEMENTED ****
return null;
}
}
public MyException extends Exception{
....
}
下面是我写的测试class。不幸的是,我遇到了 Mockito.when(myFinalClass).getObject(name).thenReturn(Mockito.mock(Object.b)) 的问题,因为它似乎没有被调用。
@ContextConfiguration(locations = "classpath:applicationContext-test.xml")
@RunWith(PowerMockRunner.class)
public class MyAbstractClassTest {
public static class ExampleConcreteClass extends MyAbstractClass{
}
@InjectMocks
ExampleConcreteClass exampleConcreteClass;
@Mock
MyFinalClass myFinalClass;
@Before
public void setUp(){
MockitoAnnotations.initMocks(this);
}
@Test
public void testMyConcreteMethod(){
try{
Mockito.when(myFinalClass).getObject(name).
thenThrow(new MyException());
exampleConcreteClass.myConcreteMethod();
Assert.fail();
}catch(MyException e){
Assert.assertTrue(Boolean.TRUE);
}
}
}
由于MyFinalClass中getObject(String name)方法的实现还没有完成,我在调用getObject方法时抛出new MyException()。但是,由于未调用 Mockito.when(...) 调用,因此不会引发异常,从而导致断言失败。
请帮忙。谢谢。
Mockito 无法模拟最终的 classes。有几种方法可以解决这个问题。
1) 在 MyAbstractClass
中考虑不引用最终的 class,而是引用 MyFinalClass
实现(或扩展)的接口或抽象 class。所以假设 MyFinalClass
实现了一个名为 MyGettableApi
的接口。然后 MyAbstractClass
看起来像这样。
public abstract class MyAbstractClass{
@Autowired
private MyGettableApi gettableService;
//concrete method
protected Object myConcreteMethod(String name){
try{
Object b = gettableService.getObject(name);
return b;
} catch(MyException e){
LOGGER.log("ERROR THROWN" + e);
}
}
}
public final class MyFinalClass implements MyGettableApi {
@Override
public Object getObject(String name) throws MyException{
**** HAS NOT YET BEEN IMPLEMENTED ****
return null;
}
}
public interface MyGettableApi {
public Object getObject(String name);
}
现在您可以在您的测试代码中模拟 MyGettableApi
,因为它不是最终的,没有问题。
@Mock
MyGettableApi myFinalClass;
2) 解决此问题的另一种方法是将对 myFinalClass.getObject(name);
的调用包装在另一个方法中。
public abstract class MyAbstractClass{
@Autowired
private MyFinalClass myFinalClass;
//concrete method
protected Object myConcreteMethod(String name){
try{
Object b = myGetObjectWrapperMethod(name);
return b;
} catch(MyException e){
LOGGER.log("ERROR THROWN" + e);
}
}
Object myGetObjectWrapperMethod(String name) {
return myFinalClass.getObject(name);
}
}
现在在您的测试代码中,您将 @Spy
正在测试的 MyAbstractClass
实例。
@InjectMocks
@Spy
ExampleConcreteClass exampleConcreteClass;
然后你可以模拟我们的新包装器方法。
doThrow(new MyException()).when(exampleConcreteClass).myGetObjectWrapperMethod(name);
我正在使用 Mockito 服务来测试可能在 MyFinalClass 中抛出并在 MyAbstractClass 中捕获的异常,因为具体方法调用 MyFinalClass 中的 getObject 方法。
请看下面的代码。
public abstract class MyAbstractClass{
@Autowired
private MyFinalClass myFinalClass;
//concrete method
protected Object myConcreteMethod(String name){
try{
Object b = myFinalClass.getObject(name);
return b;
} catch(MyException e){
LOGGER.log("ERROR THROWN" + e);
}
}
}
public final class MyFinalClass {
public Object getObject(String name) throws MyException{
**** HAS NOT YET BEEN IMPLEMENTED ****
return null;
}
}
public MyException extends Exception{
....
}
下面是我写的测试class。不幸的是,我遇到了 Mockito.when(myFinalClass).getObject(name).thenReturn(Mockito.mock(Object.b)) 的问题,因为它似乎没有被调用。
@ContextConfiguration(locations = "classpath:applicationContext-test.xml")
@RunWith(PowerMockRunner.class)
public class MyAbstractClassTest {
public static class ExampleConcreteClass extends MyAbstractClass{
}
@InjectMocks
ExampleConcreteClass exampleConcreteClass;
@Mock
MyFinalClass myFinalClass;
@Before
public void setUp(){
MockitoAnnotations.initMocks(this);
}
@Test
public void testMyConcreteMethod(){
try{
Mockito.when(myFinalClass).getObject(name).
thenThrow(new MyException());
exampleConcreteClass.myConcreteMethod();
Assert.fail();
}catch(MyException e){
Assert.assertTrue(Boolean.TRUE);
}
}
}
由于MyFinalClass中getObject(String name)方法的实现还没有完成,我在调用getObject方法时抛出new MyException()。但是,由于未调用 Mockito.when(...) 调用,因此不会引发异常,从而导致断言失败。
请帮忙。谢谢。
Mockito 无法模拟最终的 classes。有几种方法可以解决这个问题。
1) 在 MyAbstractClass
中考虑不引用最终的 class,而是引用 MyFinalClass
实现(或扩展)的接口或抽象 class。所以假设 MyFinalClass
实现了一个名为 MyGettableApi
的接口。然后 MyAbstractClass
看起来像这样。
public abstract class MyAbstractClass{
@Autowired
private MyGettableApi gettableService;
//concrete method
protected Object myConcreteMethod(String name){
try{
Object b = gettableService.getObject(name);
return b;
} catch(MyException e){
LOGGER.log("ERROR THROWN" + e);
}
}
}
public final class MyFinalClass implements MyGettableApi {
@Override
public Object getObject(String name) throws MyException{
**** HAS NOT YET BEEN IMPLEMENTED ****
return null;
}
}
public interface MyGettableApi {
public Object getObject(String name);
}
现在您可以在您的测试代码中模拟 MyGettableApi
,因为它不是最终的,没有问题。
@Mock
MyGettableApi myFinalClass;
2) 解决此问题的另一种方法是将对 myFinalClass.getObject(name);
的调用包装在另一个方法中。
public abstract class MyAbstractClass{
@Autowired
private MyFinalClass myFinalClass;
//concrete method
protected Object myConcreteMethod(String name){
try{
Object b = myGetObjectWrapperMethod(name);
return b;
} catch(MyException e){
LOGGER.log("ERROR THROWN" + e);
}
}
Object myGetObjectWrapperMethod(String name) {
return myFinalClass.getObject(name);
}
}
现在在您的测试代码中,您将 @Spy
正在测试的 MyAbstractClass
实例。
@InjectMocks
@Spy
ExampleConcreteClass exampleConcreteClass;
然后你可以模拟我们的新包装器方法。
doThrow(new MyException()).when(exampleConcreteClass).myGetObjectWrapperMethod(name);