According to the documentation, non stubbed methods return null.
I want to test a method that should return "null" under some circumstances, however the test fails with the exception indicating the method was not called.
This is the test init function:
#Before
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
mDataEntry = getFakeEntry();
when(mRepository.getEntry(1L)).thenReturn(mDataEntry);
mGetEntry = new GetEntryImpl(mRepository);
}
and this is the failed test:
#SuppressWarnings("unchecked")
#Test
public void testGetEntry_failure() throws Exception {
mGetEntry.execute(2L, mCallback);
verify(mRepository).getEntry(eq(2L));
verify(mCallback).onError(anyString(), Mockito.any(Exception.class));
}
the execute method calls the mocked object mRepository function getEntry(2L) which I was expecting to return null. However, this is what Mockito tells me when I run the test:
Wanted but not invoked:
mRepository.getEntry(2);
-> at com.xyz.interactor.GetEntryTest.testGetEntry_failure(GetEntryTest.java:54)
Actually, there were zero interactions with this mock.
I tried adding
when(mRepository.getEntry(2L)).thenReturn(null);
to the init function, but it makes no difference. If I return a valid object instead of null, then the test fails as expected, because the onError function is not called (so the mocked object's function for value 2L is being called when I specify a valid return value).
How can I have the mocked object return null for a set of values?
Edit:
here's the code for the function under test:
#Override
public void execute(final long id, final Callback<DataEntry> callback) {
AsyncTask.execute(new Runnable() {
#Override
public void run() {
DataEntry dataEntry = mDataEntryRepository.getEntry(id);
if (dataEntry != null) {
callback.onResult(dataEntry);
} else {
callback.onError("TODO", null);
}
}
});
}
and for reference, the success test works:
#SuppressWarnings("unchecked")
#Test
public void testGetEntry_success() throws Exception {
mGetEntry.execute(1L, mCallback);
verify(mRepository).getEntry(eq(1L));
verify(mCallback).onResult(eq(mDataEntry));
}
I don't think the problem is with Mockito default values / returning null.
I wrote a modified SSCCE, and the tests run fine for me. I don't have the android API, so I couldn't use the AsynchTask.execute(). From what I understand, this code would run in a separate thread, so you might not be guaranteed that the code was run before verify is called. If you take out the AsynchTask and implement execute as follows, does it still fail? Is it possible for an exception to be thrown in execute?
public void execute( final long id, final Callback<DataEntry> callback) {
DataEntry dataEntry = mDataEntryRepository.getEntry(id);
if (dataEntry != null) {
callback.onResult(dataEntry);
} else {
callback.onError("TODO", null);
}
}
Related
I am trying to write unit test cases for one of the methods in code.Below is the method
public boolean isValid() {
if(object == null)
return false
//do something here and return value.
}
The object is created by this method which is done before without getter setter method.
private Object returnObject() {
object = Axis2ConfigurationContextFactory.getConfigurationContext();
return object;
}
When I try to test isValid(), the object is always null, so it never goes in the code to do something.
I was checking if there is any way to skip that line or make the object not null. I also tried creating an object using returnObject method. But it uses Axis library classes which throws error if it does not find certain data. What can be done in this case? I am dealing with legacy code so any pointers would be helpful.
Edit : Adding test implementation.
#PowerMockIgnore({ "javax.xml.*", "org.w3c.dom.*", "javax.management.*" })
public class ClassTest {
private ClassTest classTestObj;
#BeforeMethod
public void callClassConstructor() {
classTestObj = //call class constructor
}
#BeforeClass
public void setUpClass() throws Exception {
MockitoAnnotations.initMocks(this);
}
#Test
public boolean isValidTest() {
Boolean result = classTestObj.isValid();
Assert.assertEquals(result);
}
}
As I mentioned in the before comment, you can make use of MockedStatic to mock the static method - https://javadoc.io/static/org.mockito/mockito-core/4.4.0/org/mockito/Mockito.html#static_mocks
So your code will somewhat look like the below one if you are making use of Mockito instead of PowerMockito.
#RunWith(MockitoJUnitRunner.class)
public class ClassTest
{
#Mock
private Object mockAxis2ConfigurationContextFactoryObject;
#Test
public boolean isValidTest() {
try (MockedStatic<Axis2ConfigurationContextFactory> mockedStatic = mockStatic(Axis2ConfigurationContextFactory.class)) {
mockedStatic.when(()->Axis2ConfigurationContextFactory.getConfigurationContext()).thenReturn(mockAxis2ConfigurationContextFactoryObject);
Boolean result = classTestObj.isValid();
Assert.assertEquals(result);
}
}
I am trying to test following method:
public void execute(Publisher<T> publisher) throws Exception {
PublishStrategy<T> publishStrategy = publisher.getPublishStrategy();
publishStrategy.execute(publisher::executionHandler);
}
Following is the Junit code:
#Test
public void testExecute() throws Exception {
PublishStrategy<Event> publishStrategy = Mockito.mock(PublishStrategy.class);
Publisher<Event> publisher = Mockito.mock(Publisher.class);
Mockito.when(publisher.getPublishStrategy()).thenReturn(publishStrategy);
Mockito.doNothing().when(publishStrategy).execute(publisher::executionHandler);
PublishJob job = new PublishJob(publisher);
job.execute(publisher);
Mockito.verify(publishStrategy, Mockito.times(1)).execute(publisher::executionHandler);
}
On the verify method call, I am getting following mockito exception:
Argument(s) are different! Wanted:
publishStrategy.execute(
com.test.producer.jobs.PublishJobTest$$Lambda$3/1146825051#6f45df59
);
-> at com.test.producer.jobs.PublishJobTest.testExecute(PublishJobTest.java:23)
Actual invocation has different arguments:
publishStrategy.execute(
com.producer.jobs.PublishJob$$Lambda$2/1525409936#38e79ae3
);
-> at com.producer.jobs.PublishJob.execute(PublishJob.java:30)
I don't understand why mockito considers both the lambda's are different?
Update
I solved it without using Mockito.
Here's the other approach. Omitted empty overridden methods:
#Test
public void testExecute() throws Exception {
PublishStrategy<Event> publishStrategy = new PublishStrategy<Event>() {
#Override
public void execute(Consumer<List<Event>> handler) {
Assert.assertNotNull(handler);
}
};
Publisher<Event> publisher = new AbstractPublisher<Event>() {
#Override
public void init(PublishStrategy<Event> publishStrategy) {
this.publishStrategy = publishStrategy;
}
#Override
public void executionHandler(List<IngestEvent> items) {
}
#Override
public PublishStrategy<IngestEvent> getPublishStrategy() {
return this.publishStrategy;
}
};
publisher.init(publishStrategy);
PublishJob job = new PublishJob();
job.execute(publisher);
}
In Java, two objects aren't equal because they are instances of the same class! Objects are equal because calling a.equals(b) returns true!
In your case, that class PublishJob probably doesn't override the equals method. So, comparing two lambda instances results in false. And note: I really don't see how you could fix this by adding an equals method.
In other words: when you do publisher::executionHandler you create two different lambda instances. It doesn't matter that they will both make a call on the same object. You have two lambda instances. And they are simply not equal. And that Mockito method checks for equality.
I think one way how to test this: see if you can get that lambda to be executed. Then verify that the expected call takes place on that object.
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 trying to figure out, how to re-run failed tests with usage of Espresso. I think it's a bit more complicated from common JUnit test case as you need to restore status in your app from before test start.
My approach is to create my own ActivityTestRule so I just copied whole code from this class and named it MyActivityTestRule.
In case of instrumentation tests rule will also need information of how we want to start our activity. I prefer to launch it myself rather than have environment to do it for me. So for example:
#Rule
public MyActivityTestRule<ActivityToStartWith> activityRule = new MyActivityTestRule<>(
ActivityToStartWith.class, true, false
);
So I also launch my activity in #Before annotation method:
#Before
public void setUp() throws Exception {
activityRule.launchActivity(new Intent());
}
And make clean up in #After annotation method:
#After
public void tearDown() throws Exception {
cleanUpDataBaseAfterTest();
returnToStartingActivity(activityRule);
}
Those methods - setUp(), tearDown() are essential to be called before/after each test run - to ensure the app state during the test start is correct.
Inside MyActivityTestRule I did few modifications so far. First thing is change of apply method from:
#Override
public Statement apply(final Statement base, Description description) {
return new ActivityStatement(super.apply(base, description));
}
It's a but unknown thing for me, as ActivityStatement placed in ActivityTestRule has super.apply method so it also wraps test statement in UiThreadStatement:
public class UiThreadStatement extends Statement {
private final Statement mBase;
private final boolean mRunOnUiThread;
public UiThreadStatement(Statement base, boolean runOnUiThread) {
mBase = base;
mRunOnUiThread = runOnUiThread;
}
#Override
public void evaluate() throws Throwable {
if (mRunOnUiThread) {
final AtomicReference<Throwable> exceptionRef = new AtomicReference<>();
getInstrumentation().runOnMainSync(new Runnable() {
public void run() {
try {
mBase.evaluate();
} catch (Throwable throwable) {
exceptionRef.set(throwable);
}
}
});
Throwable throwable = exceptionRef.get();
if (throwable != null) {
throw throwable;
}
} else {
mBase.evaluate();
}
}
}
No mather what I do with my tests I can never create case mRunOnUiThread boolean to be true. It will be true if within my test cases, tests with annotation #UiThreadTest will be present - or that's what I understood from code. It never happens though, I don't use anything like that so I decided to ignore this UiThreadStatement and change MyActivityTestRule to:
#Override
public Statement apply(final Statement base, Description description) {
return new ActivityStatement(base);
}
And my test cases run without any problem. Thanks to that all I have left - that wraps around mBase.evaluate() is:
private class ActivityStatement extends Statement {
private final Statement mBase;
public ActivityStatement(Statement base) {
mBase = base;
}
#Override
public void evaluate() throws Throwable {
try {
if (mLaunchActivity) {
mActivity = launchActivity(getActivityIntent());
}
mBase.evaluate();
} finally {
finishActivity();
afterActivityFinished();
}
}
}
In general launchActivity will be called only if I set in the 3rd parameter of ActivityTestRule constructor value true. But I launch tests by myself in setUp() so it never happens.
From what I understood mBase.evaluate() runs my code inside #Test annotation method. It also stops the test case during throwable being thrown. That means I can catch it and restart it - like proposed there:
How to Re-run failed JUnit tests immediately?
And okay I did something like that:
public class ActivityRetryStatement extends Statement {
private final Statement mBase;
private final int MAX_RUNS = 2;
public ActivityRetryStatement(Statement base) {
mBase = base;
}
#Override
public void evaluate() throws Throwable {
Throwable throwable = null;
for (int i = 0; i < MAX_RUNS; i++) {
try {
mBase.evaluate();
// if you reach this lane that means evaluate passed
// and you don't need to do the next run
break;
} catch (Throwable t) {
// save first throwable if occurred
if (throwable == null) {
throwable = t;
}
// my try that didn't work
launchActivity(testInitialIntent);
// I've returned test to starting screen but
// mBase.envaluate() didn't make it run again
// it would be cool now to:
// - invoke #After
// - finish current activity
// - invoke #Before again and start activity
// - mBase.evaluate() should restart #Test on activity started again by #Before
}
}
finishActivity();
afterActivityFinished();
// if 1st try fail but 2nd passes inform me still that there was error
if (throwable != null) {
throw throwable;
}
}
}
So those comments in catch block are parts I don't know how to do. I tried to perform launchActivity on intent I used in setUp() to run the test for the 1st time. But mBase.evaluate() didn't make it react (test case didn't go again) - nothing happened + it wouldn't really save me there I think. I lacked some initiations I do in #SetUp, it wasn't called again. I would really like to find a way how to properly restart whole test lifecycle #Before #Test #After over again. Maybe some call on Instrumentation or TestRunner from code.
Any thoughts about how it could be done?
You can use https://github.com/AdevintaSpain/Barista library for rerunning failed tests.
You can see more details about dealing with flaky tests here: https://github.com/AdevintaSpain/Barista#dealing-with-flaky-tests
The answer is super simple. Just make sure you upgrade your espresso tests to Junit 4, and then see this answer
This is my first post in Stackoverflow, so far I have been the active reader of this forum and I am posting my first question here.
This is regarding the EasyMock usage, I am a new user of EasyMock and in the following example code I am setting expectation for a collaborator method with the same object to be returned (doesn't matter whether it is same object or different object but the result is same) and I am resetting before going out of the test method. but when the second test is executed, the mocked method is returning null, I am not sure why is this happening.
If I run the methods
#RunWith(PowerMockRunner.class)
#PrepareForTest({CollaboratorWithMethod.class, ClassTobeTested.class})
public class TestClassTobeTested {
private TestId testId = new TestId();
#Test
public void testMethodtoBeTested() throws Exception{
CollaboratorWithMethod mockCollaborator = EasyMock.createMock(CollaboratorWithMethod.class);
PowerMock.expectNew(CollaboratorWithMethod.class).andReturn(mockCollaborator);
EasyMock.expect(mockCollaborator.testMethod("test")).andReturn(testId);
PowerMock.replay(CollaboratorWithMethod.class);
EasyMock.replay(mockCollaborator);
ClassTobeTested testObj = new ClassTobeTested();
try {
testObj.methodToBeTested();
} finally {
EasyMock.reset(mockCollaborator);
PowerMock.reset(CollaboratorWithMethod.class);
}
}
#Test
public void testMothedtoBeTestWithException() throws Exception {
CollaboratorWithMethod mockCollaborator = EasyMock.createMock(CollaboratorWithMethod.class);
PowerMock.expectNew(CollaboratorWithMethod.class).andReturn(mockCollaborator);
EasyMock.expect(mockCollaborator.testMethod("test")).andReturn(testId);
PowerMock.replay(CollaboratorWithMethod.class);
EasyMock.replay(mockCollaborator);
ClassTobeTested testObj = new ClassTobeTested();
try {
testObj.methodToBeTested();
} finally {
EasyMock.reset(mockCollaborator);
PowerMock.reset(CollaboratorWithMethod.class);
}
}
}
Here is my Collaborator class
public class CollaboratorWithMethod {
public TestId testMethod(String text) throws IllegalStateException {
if (text != null) {
return new TestId();
} else {
throw new IllegalStateException();
}
}
}
And here is my class under test
public class ClassTobeTested {
public static final CollaboratorWithMethod collaborator = new CollaboratorWithMethod();
public void methodToBeTested () throws IOException{
try {
TestId testid = collaborator.testMethod("test");
System.out.println("Testid returned "+ testid);
} catch (IllegalStateException e) {
throw new IOException();
}
}
}
I am looking for help from you guys to understand what exactly is happening here
The collaborator variable in class ClassTobeTested is final. The first test case initalizes the variable with mock object. The second test case cannot initialize the variable again. You set the expectation on the mock object created in second test case but actually the variable is still referring to the first mocked object.
Since you do not want to modify the class, you should set the mock reference once using #BeforeClass and make "mockCollaborator" a global variable so that you can use the reference in multiple test cases.