Reputation: 37
I am using Mockito services to test the Exception that could be thrown in MyFinalClass2 and be caught in MyAbstractClass as the concrete method makes a call to the getValue method in MyFinalClass2. This method returns an interface (MyInterfaceClass) object.
I asked a question earlier in Mocking Chained calls in Concrete Class Mockito and thankfully, the solution provided works when calling the getObject method found in MyFinalClass . Therefore, test1 works!
However, this time I have another final class (MyFinalClass2) which is not @Autowired, and is called after a call to a method in MyFinalClass. An Object of type MyFinalClass2 is return from the first call to method in MyFinalClass. When manually throwing a MyException2 in test2 , it does not get recognized and therefore causes an AssertionFailure in Test2 .
Also please note, the below line of code returns NULL as it has not yet been implemented. Which is the reason why I am returning in Test2 a new instance of MyFinalClass2 when this method is called.
MyFinalClass2 myFinalClass2 = getObject(strName);
Please see below code.
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);
}
}
}
Please help. Greatly Appreciated!
Upvotes: 0
Views: 501
Reputation: 10652
First of all, I am sorry to say so, but if you need to think that hard about testing, it's normally a sure sign that the code is bad. Anway, you don't need PowerMock there, since Mockito 2 is able to mock final classes already (you have to opt-in for that, though).
Also your test doesn't make any sense at all, since your exampleConcreteClass.myConcreteMethod()
cannot throw a MyException2
, because...
} catch(MyException2 e){
LOGGER.log("ERROR THROWN" + e);
}
...thus the MyException2
will never leave the scope of the method, but be transformed into a log message there and then be discarded. It will not leave the method, thus trying to assert it will not work. You would have something like throw e;
there, too:
} catch(MyException2 e){
LOGGER.log("ERROR THROWN" + e);
throw e; // re-throw e, otherwise it ends here
}
Also, just as a hint, what you are trying to do there can be more easily done by simple writing...
@Test(expected=MyException2.class)
public void testIfExceptionTwoIsThrown() throws MyException, MyException2 {
...this way, you can remove all the try-catch stuff from your test method, since JUnit will automatically fail the test if no MyException2 is thrown. Alternatively, if you want to have more control, you can even have a look at JUnit's ExpectedException rule, which is a little bit more powerful and versatile than just the expected
parameter (but that one should be enough for this case).
But of course, nothing changes the fact that, as long as your method catches your MyException2, it will not leave said method, so testing for it will not help.
Upvotes: 3