Mockito 链式方法调用依赖于无法识别的先前调用
Mockito chained method calls relying on previous call not recognized
我正在使用 Mockito 服务来测试可能在 MyFinalClass2 中抛出并在 MyAbstractClass 中捕获的异常,因为具体方法调用 MyFinalClass2 中的 getValue 方法。此方法 return 是一个接口 (MyInterfaceClass) 对象。
我早些时候在 中问过一个问题,幸运的是,提供的解决方案在调用 MyFinalClass 中的 getObject 方法时有效。因此,test1 有效!
然而,这次我有另一个final class (MyFinalClass2),它不是@Autowired,是在调用MyFinalClass 中的方法之后调用的。 MyFinalClass2 类型的对象是 return 从第一次调用 MyFinalClass 中的方法。在 test2 中手动抛出 MyException2 时,它不会被识别,因此会导致 Test2 中出现 AssertionFailure。
另请注意,下面的代码行 returns NULL,因为它尚未实现。这就是为什么我在调用此方法时 return 在 Test2 中创建 MyFinalClass2 的新实例的原因。
MyFinalClass2 myFinalClass2 = getObject(strName);
请看下面的代码。
public abstract class MyAbstractClass{
@Autowired
private MyFinalClass myFinalClass;
//concrete method
protected MyInterfaceClass myConcreteMethod(String strName, String str)
{
try{
//returns null as it has not yet been implemented
MyFinalClass2 myFinalClass2 = getObject(strName);
MyInterfaceClass b = getValue(myFinalClass2,str);
return b;
} catch(MyException e){
LOGGER.log("ERROR THROWN" + e);
} catch(MyException2 e){
LOGGER.log("ERROR THROWN" + e);
}
}
public MyFinalClass2 getObject(String strName){
return myFinalClass.getObject(strName);
}
public MyInterfaceClass getValue(MyFinalClass2 myFinalClass2, String
str){
return myFinalClass2.getValue(str);
}
}
public final class MyFinalClass {
public MyFinalClass2 getObject(String strName) throws MyException{
**** HAS NOT YET BEEN IMPLEMENTED ****
return null;
}
}
public final class MyFinalClass2 {
public MyInterfaceClass getValue(String str) throws MyException2{
**** HAS NOT YET BEEN IMPLEMENTED ****
return null;
}
}
public interface MyInterfaceClass {
**** HAS NOT YET BEEN IMPLEMENTED BY ANY CLASS ****
void getStuff();
}
@ContextConfiguration(locations = "classpath:applicationContext-test.xml")
@RunWith(PowerMockRunner.class)
public class MyAbstractClassTest {
public static class ExampleConcreteClass extends MyAbstractClass{
}
@InjectMocks
@Spy
ExampleConcreteClass exampleConcreteClass;
@Before
public void setUp(){
MockitoAnnotations.initMocks(this);
}
//THIS WORKS --- TEST 1
@Test
public void testIfExceptionOneIsThrown(){
try{
Mockito.when(exampleConcreteClass).getObject(name).
thenThrow(new MyException());
exampleConcreteClass.myConcreteMethod();
Assert.fail();
}catch(MyException e){
Assert.assertTrue(Boolean.TRUE);
}
}
//This test DOES NOT work --- TEST 2
@Test
public void testIfExceptionTwoIsThrown(){
try{
MyFinalClass2 myFinClass2 = new MyFinalClass2();
String strName = "name";
String str = "str";
Mockito.when(exampleConcreteClass).getValue(myFinClass2,str).
thenThrow(new MyException2());
Mockito.when(exampleConcreteClass).getObject(strName).
thenReturn(myFinClass2);
exampleConcreteClass.myConcreteMethod();
Assert.fail();
}catch(MyException e){
Assert.fail();
}catch(MyException2 e){
Assert.assertTrue(Boolean.TRUE);
}
}
}
请帮忙。非常感谢!
首先,我很抱歉这么说,但如果您需要认真考虑测试,通常这就是代码错误的明确标志。无论如何,你在那里不需要 PowerMock,因为 Mockito 2 已经能够 mock final classes(不过你必须选择加入)。
此外,您的测试根本没有任何意义,因为您的 exampleConcreteClass.myConcreteMethod()
无法抛出 MyException2
,因为...
} catch(MyException2 e){
LOGGER.log("ERROR THROWN" + e);
}
...因此 MyException2
永远不会离开方法的范围,而是在那里转换为日志消息然后被丢弃。它不会离开该方法,因此尝试断言它不会起作用。你也会有类似 throw e;
的东西:
} catch(MyException2 e){
LOGGER.log("ERROR THROWN" + e);
throw e; // re-throw e, otherwise it ends here
}
此外,作为提示,您在那里尝试做的事情可以通过简单的书写更容易地完成...
@Test(expected=MyException2.class)
public void testIfExceptionTwoIsThrown() throws MyException, MyException2 {
...这样,您可以从测试方法中删除所有 try-catch 内容,因为如果没有抛出 MyException2,JUnit 将自动使测试失败。或者,如果你想拥有更多的控制权,你甚至可以看看 JUnit 的 ExpectedException 规则,它比 expected
参数更强大和通用(但那个应该足够了对于这种情况)。
但是,当然,没有什么能改变一个事实,只要你的方法捕获了你的 MyException2,它就不会离开所述方法,因此对其进行测试将无济于事。
我正在使用 Mockito 服务来测试可能在 MyFinalClass2 中抛出并在 MyAbstractClass 中捕获的异常,因为具体方法调用 MyFinalClass2 中的 getValue 方法。此方法 return 是一个接口 (MyInterfaceClass) 对象。
我早些时候在
然而,这次我有另一个final class (MyFinalClass2),它不是@Autowired,是在调用MyFinalClass 中的方法之后调用的。 MyFinalClass2 类型的对象是 return 从第一次调用 MyFinalClass 中的方法。在 test2 中手动抛出 MyException2 时,它不会被识别,因此会导致 Test2 中出现 AssertionFailure。
另请注意,下面的代码行 returns NULL,因为它尚未实现。这就是为什么我在调用此方法时 return 在 Test2 中创建 MyFinalClass2 的新实例的原因。
MyFinalClass2 myFinalClass2 = getObject(strName);
请看下面的代码。
public abstract class MyAbstractClass{
@Autowired
private MyFinalClass myFinalClass;
//concrete method
protected MyInterfaceClass myConcreteMethod(String strName, String str)
{
try{
//returns null as it has not yet been implemented
MyFinalClass2 myFinalClass2 = getObject(strName);
MyInterfaceClass b = getValue(myFinalClass2,str);
return b;
} catch(MyException e){
LOGGER.log("ERROR THROWN" + e);
} catch(MyException2 e){
LOGGER.log("ERROR THROWN" + e);
}
}
public MyFinalClass2 getObject(String strName){
return myFinalClass.getObject(strName);
}
public MyInterfaceClass getValue(MyFinalClass2 myFinalClass2, String
str){
return myFinalClass2.getValue(str);
}
}
public final class MyFinalClass {
public MyFinalClass2 getObject(String strName) throws MyException{
**** HAS NOT YET BEEN IMPLEMENTED ****
return null;
}
}
public final class MyFinalClass2 {
public MyInterfaceClass getValue(String str) throws MyException2{
**** HAS NOT YET BEEN IMPLEMENTED ****
return null;
}
}
public interface MyInterfaceClass {
**** HAS NOT YET BEEN IMPLEMENTED BY ANY CLASS ****
void getStuff();
}
@ContextConfiguration(locations = "classpath:applicationContext-test.xml")
@RunWith(PowerMockRunner.class)
public class MyAbstractClassTest {
public static class ExampleConcreteClass extends MyAbstractClass{
}
@InjectMocks
@Spy
ExampleConcreteClass exampleConcreteClass;
@Before
public void setUp(){
MockitoAnnotations.initMocks(this);
}
//THIS WORKS --- TEST 1
@Test
public void testIfExceptionOneIsThrown(){
try{
Mockito.when(exampleConcreteClass).getObject(name).
thenThrow(new MyException());
exampleConcreteClass.myConcreteMethod();
Assert.fail();
}catch(MyException e){
Assert.assertTrue(Boolean.TRUE);
}
}
//This test DOES NOT work --- TEST 2
@Test
public void testIfExceptionTwoIsThrown(){
try{
MyFinalClass2 myFinClass2 = new MyFinalClass2();
String strName = "name";
String str = "str";
Mockito.when(exampleConcreteClass).getValue(myFinClass2,str).
thenThrow(new MyException2());
Mockito.when(exampleConcreteClass).getObject(strName).
thenReturn(myFinClass2);
exampleConcreteClass.myConcreteMethod();
Assert.fail();
}catch(MyException e){
Assert.fail();
}catch(MyException2 e){
Assert.assertTrue(Boolean.TRUE);
}
}
}
请帮忙。非常感谢!
首先,我很抱歉这么说,但如果您需要认真考虑测试,通常这就是代码错误的明确标志。无论如何,你在那里不需要 PowerMock,因为 Mockito 2 已经能够 mock final classes(不过你必须选择加入)。
此外,您的测试根本没有任何意义,因为您的 exampleConcreteClass.myConcreteMethod()
无法抛出 MyException2
,因为...
} catch(MyException2 e){
LOGGER.log("ERROR THROWN" + e);
}
...因此 MyException2
永远不会离开方法的范围,而是在那里转换为日志消息然后被丢弃。它不会离开该方法,因此尝试断言它不会起作用。你也会有类似 throw e;
的东西:
} catch(MyException2 e){
LOGGER.log("ERROR THROWN" + e);
throw e; // re-throw e, otherwise it ends here
}
此外,作为提示,您在那里尝试做的事情可以通过简单的书写更容易地完成...
@Test(expected=MyException2.class)
public void testIfExceptionTwoIsThrown() throws MyException, MyException2 {
...这样,您可以从测试方法中删除所有 try-catch 内容,因为如果没有抛出 MyException2,JUnit 将自动使测试失败。或者,如果你想拥有更多的控制权,你甚至可以看看 JUnit 的 ExpectedException 规则,它比 expected
参数更强大和通用(但那个应该足够了对于这种情况)。
但是,当然,没有什么能改变一个事实,只要你的方法捕获了你的 MyException2,它就不会离开所述方法,因此对其进行测试将无济于事。