Mockito链接方法调用依赖于之前的调用未被识别

时间:2017-08-26 18:52:18

标签: java junit mockito powermock powermockito

我正在使用Mockito服务来测试可能在MyFinalClass2中抛出的异常并在MyAbstractClass中捕获,因为具体方法调用了MyFinalClass2中的getValue方法。此方法返回一个接口(MyInterfaceClass)对象。

我之前在Mocking Chained calls in Concrete Class Mockito中提出了一个问题,谢天谢地,提供的解决方案在调用MyFinalClass中的getObject方法时起作用。因此,test1有效!

但是,这次我有另一个不是@Autowired的最终类(MyFinalClass2),并且在调用MyFinalClass中的方法之后调用。 MyFinalClass2类型的Object是从第一次调用MyFinalClass中的方法返回的。在test2中手动抛出MyException2时,它不会被识别,因此在Test2中导致AssertionFailure。

另请注意,下面的代码行返回NULL,因为它尚未实现。这就是为什么我在调用此方法时在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);
        }
   }

}

请帮忙。非常赞赏!

1 个答案:

答案 0 :(得分:3)

首先,我很遗憾地这么说,但如果你需要认真考虑测试,通常肯定是代码不好。不管怎么说,你不需要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,它就不会离开所述方法,因此测试它将无济于事。