I have the following scenario:
public class ClassA {
public void methodA(){
try {
int result=methodB();
} catch (IOException e) {
//Some code here
}
}
private int methodB() throws IOException{
//Some code here
return 1;
}
}
I want to cover the catch block of the public method methodA() in my test. I don't want to change the visibility of the private method. Is there any way to achieve partial mock of private method using EasyMock? Or is there any way to change the behaviour of private method in my Junit class to throw exception without using mocking?
Thanks in advance.
You cannot do this with Easymock alone, you can do this with a combination of EasyMock and Powermock. Then you mock the return value of the private method.
To test the catch block, you must tell EasyMock to throw an exception when calling methodB.
From the docs:
For specifying exceptions (more exactly: Throwables) to be thrown, the object returned
by expectLastCall() and expect(T value) provides the method andThrow(Throwable throwable).
The method has to be called in record state after the call to the Mock Object for which
it specifies the Throwable to be thrown.
Example:
expectLastCall().andThrow(new IOException("Now to test catch block..."));
Related
I'm using Mockito to test a method that internally makes a networking call and returns a value based on the result of the networking call. This method uses a SynchronousQueue to wait for the result, and the result is set by the callback for the networking call:
HelperClass helperClassObject = new HelperClassObject();
...
public SomeResultCode methodWithNetworkCall() {
SynchronousQueue<SomeResultCode> resultQueue = new SynchronousQueue<>();
// some condition checking code
helperClassObject.makeNetworkCall(new GenericCallback() {
#Override
public void onSuccess(JSONObject response) {
resultQueue.offer(SomeResultCode.SUCCESS);
}
#Override
public void onFailure(VolleyError error) {
resultQueue.offer(SomeResultCode.FAILURE);
}
});
SomeResultCode resultCode = null;
try {
resultCode = resultQueue.poll(1, TimeUnit.MINUTES);
} catch (InterruptedException e) {
}
return resultCode == null ? SomeResultCode.FAILURE : resultCode;
}
In one of my unit test methods I'm trying to verify that SUCCESS is returned upon successful network call. I've tried using ArgumentCaptor and doAnswer to trigger the callback's onSuccess. However, the method is returning FAILURE. I put a breakpoint in the onSuccess, and it looks like when I use the ArgumentCaptor way the onSuccess is triggered AFTER the poll has timed out. When I use the doAnswer way, I see onSuccess called during the setup (doAnswer.when) but not after I actually call the method. What am I doing wrong?
EDIT
Stepping through the code again, it looks like answer is called from within the method I'm testing (i.e. when I call testObject.methodWithNetworkCall during my test), NOT during setup. So it is doing exactly what it is supposed to do: responding with onSuccess. But it is responding with onSuccess BEFORE poll is called. So it seems the problem is not that answer and mocking in general is not working/set up wrong, it is an issue with testing with SynchronousQueue.
Here is my test code:
public class TestClassUnitTest {
TestClass sut;
HelperClass helperClassObject = mock(HelperClass.class);
#Before
public void setup() {
sut = new TestClass();
injectField(sut, "helperClassFieldName", helperClassObject);
}
public void injectField(Object testObject, String fieldName, T mockToInject) {
// some code using reflection to inject the mock object into the test object
}
#Test
public void testMethodWithNetworkCallWithCaptor() {
ArgumentCaptor<GenericCallback> captor = ArgumentCaptor.forClass(GenericCallback.class);
SomeResultCode result = sut.methodWithNetworkcall();
verify(helperClassObject, times(1)).makeNetworkCall(captor.capture());
captor.getValue().onSuccess(new JSONObject());
Assert.assertEquals(SomeResultCode.SUCCESS, result);
}
#Test
public void testMethodWithNetworkCallWithDoAnswer() {
doAnswer(new Answer(){
#Override
public Object answer(InvocationOnMock invocation) throws Throwable {
((GenericCallback)invocation.getArguments()[0]).onSuccess(new JSONObject());
return null;
}
}).when(helperClassObject).makeNetworkCall(any(GenericCallback.class));
SomeResultCode result = sut.methodWithNetworkcall();
Assert.assertEquals(SomeResultCode.SUCCESS, result);
}
}
It looks like you're not replacing your HelperClassObject in your system-under-test, or at least you haven't shown us where you have. The mock returned by Mockito.mock (or #Mock or spy or #Spy) doesn't apply to every instance of the class you pass in; it just creates a single instance. You have to make sure to set the instance (HelperClassObject here) in your system-under-test, possibly by passing it in as a constructor parameter, setting the instance as a field, or setting it using a setter method. If you leave it as new HelperClassObject() as you've shown us, there's no way Mockito will be able to help you.
Your reference to "onSuccess called during the setup (doAnswer.when)" worries me a little bit, because if you've created a mock using Mockito.mock, there should be no reason Mockito would actually call your Answer during setup. This leads me to believe that your HelperClassObject or makeNetworkcall method can't be mocked, possibly from having limited visibility, or because they're marked static or final. Mockito effectively works by writing a custom subclass of the class you're mocking, so make sure the classes and methods you're mocking are public and non-final to ensure they're overridable. (It is possible to mock protected or package-private methods, but certain versions of Mockito have complications with certain code structures. Let's rule that out first.)
After you make sure that the class is mockable and that it's using the mocked HelperClassObject instance you pass in, you'll be able to move forward. You'll want to pursue the doAnswer structure: The ArgumentCaptor version won't work, because if your methodWithNetworkcall blocks and waits for a result, then you'll get a FAILURE return value before you ever get a chance to verify and call your callback. (That explains the timeout.) In other cases where your method-under-test can return first, the ArgumentCaptor solution will be more practical for you.
In this case using doAnswer IS the correct approach. The issue is with the way SynchronousQueue worked: it expects multi-threaded usage of this queue:
A blocking queue in which each insert operation must wait for a corresponding remove operation by another thread, and vice versa.
But in this testing case the test runs on a single thread.
Solution: mock the SynchronousQueue, and use doAnswer to get offer() and poll() to push/pop result onto a LinkedList. In the process, I also moved the SynchrnousQueue local variable resultQueue out of methodWithNetworkCall() and made it an instance member. Updated test code below:
public class TestClassUnitTest {
TestClass sut;
private LinkedList testQueue = new LinkedList();
private SynchronousQueue<SomeResultCode> resultQueueMock = mock(SynchronousQueue.class);
private HelperClass helperClassMock = mock(HelperClass.class);
#Before
public void setup() {
sut = new TestClass();
injectField(sut, "resultQueue", resultQueueMock);
injectField(sut, "helperClassFieldName", helperClassMock);
}
public void injectField(Object testObject, String fieldName, T mockToInject) {
// some code using reflection to inject the mock object into the test object
}
#Test
public void testMethodWithNetworkCallWithDoAnswer() {
doAnswer(new Answer(){
#Override
public Object answer(InvocationOnMock invocation) throws Throwable {
((GenericCallback)invocation.getArguments()[0]).onSuccess(new JSONObject());
return null;
}
}).when(helperClassMock).makeNetworkCall(any(GenericCallback.class));
mockQueue();
SomeResultCode result = sut.methodWithNetworkCall();
Assert.assertEquals(SomeResultCode.SUCCESS, result);
}
private void mockQueue() {
doAnswer(new Answer() {
#Override
public Object answer(InvocationOnMock invocation) throws Throwable {
testQueue.push(((SchedulableJob.Result)invocation.getArguments()[0]));
return true;
}
}).when(resultQueueMock).offer(any());
try {
doAnswer(new Answer() {
#Override
public Object answer(InvocationOnMock invocation) throws Throwable {
if (testQueue.size() > 0) {
return testQueue.pop();
} else {
return null;
}
}
}).when(resultQueueMock).poll(1, TimeUnit.MINUTES);
} catch (InterruptedException e) {
}
}
}
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!
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.
I have the below interface
public interface Interface1 {
Object Execute(String commandToExecute) throws Exception;
}
which then I 'm trying to mock so I can test the behaviour of the class that will call it:
Interface1 interfaceMocked = mock(Interface1.class);
when(interfaceMocked.Execute(anyString())).thenThrow(new Exception());
Interface2 objectToTest = new ClassOfInterface2(interfaceMocked);
retrievePrintersMetaData.Retrieve();
But the compiler tells me that there is an unhandled exception.
The definition of the Retrieve method is:
public List<SomeClass> Retrieve() {
try {
interface1Object.Execute("");
}
catch (Exception exception) {
return new ArrayList<SomeClass>();
}
}
The mockito documentation only shows uses of RuntimeException, and I have not seen anything on similar on StackOverflow.
I'm using Java 1.7u25 and mockito 1.9.5
Assuming your test method doesn't declare that it throws Exception, the compiler's absolutely right. This line:
when(interfaceMocked.Execute(anyString())).thenThrow(new Exception());
... calls Execute on an instance of Interface1. That can throw Exception, so you either need to catch it or declare that your method throws it.
I would personally recommend just declaring that the test method throws Exception. Nothing else will care about that declaration, and you really don't want to catch it.
You can use doAnswer method of Mockito to thrown checked exceptions, like this
Mockito.doAnswer(
invocation -> {
throw new Exception("It's not bad, it's good");
})
.when(interfaceMocked)
.Execute(org.mockito.ArgumentMatchers.anyString());
You shouldn't be having a problem if your method returns something and throws your error. Now if your method returns void you won't be able to throw an error.
Now the real thing is that you're not testing that your interface throws an exception, instead what you're testing what happens when an exception is thrown within this method.
public List<SomeClass> Retrieve() {
try {
interface1Object.Execute("");
}
catch (Exception exception) {
return handleException(exception);
}
}
protected List<SomeClass> handleException(Exception exception) {
return new ArrayList<SomeClass>();
}
Then you just call your handleException method and make sure it returns the correct thing. If you need to make sure that your interface is throwing an exception, then that is a different test for your interface class.
It might seem sucky that you are having to make a method for a single line but that's what happens sometimes if you want testable code.
I'm using EasyMock to create mock objects for JUnit testing in Java. I create a mock object and pass it to another thread where it expects methods to be called. In the other thread, the calls are enclosed in a try/catch(Throwable) block, so when an unexpected call occurs on the mock and it thus throws AssertionError, that error is caught by the catch block and treated. So, even though an unexpected call occurred, the test passes.
In order to have the test fail as expected, I would like to delay all verification of calls to the EasyMock.verify(mock) call made in the test-runner thread at the end. Is this possible and how?
I'm not sure about how to do this with EasyMock, but this behavior is possible with Mockito because verification assertions can be specified at the end of the test.
The correct solution I'd guess is to stop catching Throwable. Doing so catches all Errors as you're finding, which can be quite dangerous... are you absolutely positively 100% sure you need to catch Throwable? Why?
(If it turns out you do, you could catch AssertionError specifically and rethrow it. But that's ugly!)
Try using nice mocks:
http://easymock.org/EasyMock2_5_2_Documentation.html
"Nice Mocks
On a Mock Object returned by createMock() the default behavior for all methods is to throw an AssertionError for all unexpected method calls. If you would like a "nice" Mock Object that by default allows all method calls and returns appropriate empty values (0, null or false), use createNiceMock() instead. "
Default values will be returned for unexpected calls instead of throwing AssertionError, but you can still verify them with the verify() method (in which case the AssertionErrors will be thrown)
As #deterb suggested, it's possible with Mockito but you have to know the method name or you have to set expectations for every method. Here is an example:
The mocked interface:
public interface MyInterface {
void allowedMethod();
void disallowedMethod();
}
The user class which catches AssertionError:
public class UserClass {
public UserClass() {
}
public static void throwableCatcher(final MyInterface myInterface) {
try {
myInterface.allowedMethod();
myInterface.disallowedMethod();
} catch (final Throwable t) {
System.out.println("Catched throwable: " + t.getMessage());
}
}
}
And the Mockito test:
#Test
public void testMockito() throws Exception {
final MyInterface myInterface = mock(MyInterface.class);
UserClass.throwableCatcher(myInterface);
verify(myInterface, never()).disallowedMethod(); // fails here
}
The same is possible with EasyMock but it needs some work:
#Test
public void testEasyMock() throws Exception {
final AtomicBoolean called = new AtomicBoolean();
final MyInterface myInterface = createMock(MyInterface.class);
myInterface.allowedMethod();
myInterface.disallowedMethod();
final IAnswer<? extends Object> answer = new IAnswer<Object>() {
#Override
public Object answer() throws Throwable {
System.out.println("answer");
called.set(true);
throw new AssertionError("should not call");
}
};
expectLastCall().andAnswer(answer).anyTimes();
replay(myInterface);
UserClass.throwableCatcher(myInterface);
verify(myInterface);
assertFalse("called", called.get()); // fails here
}
Unfortunately you also have to know the method names here and you have to define expectations like myInterface.disallowedMethod() and expectLastCall().andAnswer(answer).anyTimes().
Another possibility is creating a proxy with the Proxy class (with a custom InvocationHandler) and using it as a mock object. It definitely needs more work but it could be the most customizable solution.
Finally don't forget that it's also possible to create a custom implementation with or without delegation to the EasyMock mock object. Here is one with delegation:
public class MockedMyInterface implements MyInterface {
private final MyInterface delegate;
private final AtomicBoolean called = new AtomicBoolean();
public MockedMyInterface(final MyInterface delegate) {
this.delegate = delegate;
}
#Override
public void allowedMethod() {
delegate.allowedMethod();
}
#Override
public void disallowedMethod() {
called.set(true);
throw new AssertionError("should not call");
}
public boolean isCalled() {
return called.get();
}
}
And the test for it:
#Test
public void testEasyMockWithCustomClass() throws Exception {
final MyInterface myInterface = createMock(MyInterface.class);
myInterface.allowedMethod();
final MockedMyInterface mockedMyInterface =
new MockedMyInterface(myInterface);
replay(myInterface);
UserClass.throwableCatcher(mockedMyInterface);
verify(myInterface);
assertFalse("called", mockedMyInterface.isCalled()); // fails here
}
I've the following class. It has the code to connect to SAP in its constructor. There is an abstract method(the subclasses define the implementation) which I want to mock.
public abstract class BapiExecutor {
...
public BapiExecutor(final SapConnectionInfo connectionInfo)
throws java.lang.Exception {
if (!validConnectorData()) {
throw new IllegalArgumentException(
"Does not have valid data to connect to SAP");
}
initializeState(connectionInfo);
}
public abstract Object execute() throws Exception ;
....
}
The unit I want to test is :
I want to mock the call to execute() method.
private String invokeBapiToAddAssociation(Map associationMap,
SapConnectionInfo connectionInfo) {
EidCcBapiExecutor executor = null;
String bapiExecutionResult = null;
try {
executor = new EidCcBapiExecutor(connectionInfo, associationMap);
bapiExecutionResult = (String) executor.execute();
} catch (Exception e) {
e.printStackTrace();
throw new CcGenericException(
"Exception occurred while invoking the EID-CC Association BAPI executor!",
e);
}
return bapiExecutionResult;
}
Any frameworks in Java that supports the mocking of parametrized constructors?
i just want to avoid connecting to SAP in the constructor.
JMock with the ClassImposteriser can do that, as can most good mocking frameworks.
The ClassImposteriser creates mock
instances without calling the
constructor of the mocked class. So
classes with constructors that have
arguments or call overideable methods
of the object can be safely mocked.
You can simply create the mock class, subclassing the abstract BapiExecutor class, and implementing the behavior you want in execute() (or any other method). You don't need to revert to a framework here.
Could you please elaborate about what the blocking point is ?
I expect that the EidCcBapiExecutor extends from BapiExecutor.
public class EidCcBapiExecutor extends BapiExecutor {
...
}
Than you could create the Mockup class for testing a specific method like:
public class EidCcBapiExecutorMockup extends EidCcBapiExecutor{
public EidCcBapiExecutorMockup (final SapConnectionInfo connectionInfo){
super(connectionInfo);
}
public Object execute() throws Exception {
// You mockup code
}
}
If you want to test the constructor you can create the class like:
public class EidCcBapiExecutorMockup extends EidCcBapiExecutor{
public EidCcBapiExecutorMockup (){
super(new SapConnectionInfo());
}
}
The object you place in the Constructor could be created in the setUp method of you JUnit test!