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.
Related
I have the function:
public class Cache {
(...)
public void removeAllIf(Predicate<Product> predicate) {
(...)
}
}
And I call productsCache.removeAllIf(Product::isChecked);
Currentlly I test it with
then(productsCache).should().removeAllIf(any(Predicate.class));
but this is not accurate (not testing if the passed lambda is Product::isChecked). The second problem is that I get the lint message: Unchecked assignment.
Is it better solution?
Edited:
I don't want to test removeAllIf function implementation. I want to test if removeAllIf was called with proper argument.
The scenario to test:
public class Repository {
public void removeCheckedProducts() {
remoteDataSource.removeCheckedProducts();
localDataSource.removeCheckedProducts();
cache.removeAllIf(Product::isChecked);
}
}
Unit test:
#Test
public void removeCheckedProducts() {
//when
repository.removeCheckedProducts();
//then
then(remoteDataSource).should().removeCheckedProducts();
then(localDataSource).should().removeCheckedProducts();
then(cache).should().removeAllIf(any(Predicate.class));
}
You can use ArgumentCaptor
#Captor
ArgumentCaptor<Predicate> captor = ArgumentCaptor.forClass(Predicate.class);;
#Test
public void removeCheckedProducts() {
//when
repository.removeCheckedProducts();
//then
then(remoteDataSource).should().removeCheckedProducts();
then(localDataSource).should().removeCheckedProducts();
then(cache).should().removeAllIf(captor.capture());
Predicate t = Product.checkPredicate();
assertSame(t,captor.getValue());
}
You could check removeAllIf argument behavior instead equality.
Predicate<Product> removeAllIfArgument = mockingDetails(cache).getInvocations()
.iterator()
.next()
.getArgument(0);
Product checkedProduct = mock(Product.class);
Product uncheckedProduct = mock(Product.class);
given(checkedProduct.isChecked()).willReturn(true);
given(uncheckedProduct.isChecked()).willReturn(false);
assertTrue(removeAllIfArgument.test(checkedProduct));
assertFalse(removeAllIfArgument.test(uncheckedProduct));
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 need to test if one objects calls other object methods in right order.
Unfortunately it looks like Mockito use some kind of grouping for calls with the same parameters. I prepared example which illustrates this behavior.
public class TestInOrder {
#Test
public void test() {
Foo foo = new Foo();
Bar mockBar = mock(Bar.class);
foo.run(mockBar);
InOrder order = Mockito.inOrder(mockBar);
order.verify(mockBar).A();
order.verify(mockBar).B();
order.verify(mockBar).B();
order.verify(mockBar).A();
order.verify(mockBar).B();
}
}
class Foo {
void run(Bar mockBar) {
mockBar.A();
mockBar.B();
mockBar.B();
mockBar.A();
mockBar.B();
}
}
class Bar {
public void A() {
}
public void B() {
}
}
The result is:
org.mockito.exceptions.verification.VerificationInOrderFailure:
Verification in order failure:
bar.B();
Wanted 1 time:
-> at com.goeuro.pi.provider.busfor.TestInOrder.test(TestInOrder.java:19)
But was 3 times. Undesired invocation:
-> at com.goeuro.pi.provider.busfor.Foo.run(TestInOrder.java:32)
I don't understand why I get this error. Order of calls in test is the same as in method.
The issue is that you expect one invocation on each mock. Instead Mockito will count all the invocation on certain mock and will fail when 2 in a row will happen.
This is the implementation for verify method in InOrderImpl class.
public <T> T verify(T mock) {
return this.verify(mock, VerificationModeFactory.times(1));
}
As you can see, it tells mockito to expect exact one invocation on method.
From JavaDoc:
Allows verifying exact number of invocations.
Use VerificationMode to tell Mockito how to verify you mock. This should help:
InOrder order = Mockito.inOrder(mockBar);
order.verify(mockBar).A();
order.verify(mockBar, times(2)).B();
order.verify(mockBar).A();
order.verify(mockBar).B();
I'm using Mockito with Junit version : 4.8.2
I'm not able to mock methods which expects any interface objects.
For example,
public interface If extends Xyz {
}
Class Abc {
protected List <String> getIPAddress(If x, String n) {
}
}
This is sample test method:
#Test
public void testGetIPAddress() {
Abc mockAbc = mock(Abc.class, CALLS_REAL_METHODS);
when(mockAbc.getIPAddress(any(Xyz.class), anyString())).thenReturn(new List <String>());
}
When I run the above method, I get:
NullPointerException
UPDATES
Actually I found out that the problem is using "CALLS_REAL_METHODS", when instantiating mocked object. Even if I use
when(mockAbc.getIPAddress(any(If.class), anyString())).thenReturn(null);
It is throwing NPE. The reason might be it's still calling the real method.
How do I override calling the real method in this case?
you need to call getIpAdress with an If not an Xyz
Also, new List <String>() won't work, as List is an interface, use new ArrayList<String>() instead:
#Test
public void testGetIPAddress() {
Abc mockAbc = mock(Abc.class, CALLS_REAL_METHODS);
when(mockAbc.getIPAddress(any(If.class), anyString())).thenReturn(new ArrayList<String>());
}
I still have some difficulties with Mockito. I want to have two test cases for two different object examples. So I want to simulate different method behaviour depending on argument value.
The problem is that when I run test() method, the returned value of help valiable is "b" and the assertion doesn't return true. If I comment the line marked as (***), everything works fine.
As you can see I tried to use thenAnswer instead of thenReturn, but the result was the same.
public class TestItAll {
TestClass test;
HelpClass a ;
HelpClass b;
#Before
public void init(){
a = new HelpClass("a");
b = new HelpClass("b");
Mockito.when(test.getHelp(a)).thenReturn("a");
/*Mockito.when(test.getHelp(a)).thenAnswer(
new Answer< String>() {
public String answer(InvocationOnMock invocation) {
return "a";
}
}); */
Mockito.when(test.getHelp(b)).thenReturn("b");//(***)
/*Mockito.when(test.getHelp(b)).thenAnswer(
new Answer< String>() {
public String answer(InvocationOnMock invocation) {
return "b";
}
}); */
}
#Test
public void testA(){
String help= test.getHelp(a);
Assert.assertEquals(help, "a");
}
/*#Test
public void testB(){
String help= test.getHelp(b);
Assert.assertEquals(help, "b");
}*/
}
Please, don't ask me why I'm mocking a test object. It's just a model example of a more complicated situation.
Firstly, I assume that your declaration TestClass test; is in fact TestClass test = mock(TestClass.class);, otherwise the #Before method throws NullPointerException.
When using when(test.getHelp(a)) mockito will use a's equals method to check whether the parameter matched. If e.g. equals method always returns true, it won't be able to differ a from b. I have run your code with overriding equals method (i.e. HelpClass objects are equal only if they are the same instance) and both tests have passed.
You may want to use argument matcher - when(test.getHelp(argThat(sameInstance(a)))) to not rely on your equals method. If you need something more complex than sameInstance, I would recommend sameBeanAs matcher from shazamcrest.