Mockito: wait for an invocation that matches arguments - java

I'm writing a selenium test and verifying the server behavior with mockito. Specifically, when a button is clicked, I want to make sure the page controller calls a particular method on a dependency which I've mocked.
Because it is a selenium test, I need to wait for the mock to be invoked in another thread, so I'm using mockito timeout.
verify(myMock, timeout(5000).times(1)).myMethod("expectedArg");
The trouble that I'm having is that myMethod is called many times... rather than waiting for an invocation that matches the expected arguments, timeout only waits for the first invocation.
If I use Thread.sleep(50000) rather than timeout(50000), it works as expected... but that's dirty so I'm hoping to avoid it.
How do I wait for myMethod to be invoked with the expected input?

If you are able to set a fixed number of calls to expect, it can be done with an ArgumentCaptor:
import static org.hamcrest.CoreMatchers.hasItem;
#Captor ArgumentCaptor<String> arg;
#Before
public void setUp() throws Exception {
// init the #Captor
initMocks(this);
}
#Test
public void testWithTimeoutCallOrderDoesntMatter() throws Exception {
// there must be exactly 99 calls
verify(myMock, timeout(5000).times(99)).myMethod(arg.capture());
assertThat(arg.getAllValues(), hasItem("expectedArg"));
}
Another way is to specify all the expected values to verify, but those need to be provided in the exact order that they are invoked. The difference to the above solution is that this doesn't fail even if the mock is additionally called with some non-verified arguments. In other words, no need to know the number of total invocations. Code example:
#Test
public void testWithTimeoutFollowingCallsDoNotMatter() throws Exception {
// the order until expected arg is specific
verify(callback, timeout(5000)).call("firstExpectedArg");
verify(callback, timeout(5000)).call("expectedArg");
// no need to tell more, if additional calls come after the expected arg
// verify(callback, timeout(5000)).call("randomArg");
}

This is not a super clean solution but you can do this (XX is the supposed return type here):
final CountDownLatch latch = new CountDownLatch(1);
doReturn(new Answer<XX>()
{
#Override
public XX answer(InvocationOnMock invocation)
{
latch.countDown();
return someInstanceOfXX;
}
}
).when(myMock).myMethod("expectedArg");
Then, to test if the method is called, do:
try {
assertTrue(latch.await(5L, TimeUnit.SECONDS));
} catch (InterruptedException e) {
// Urgh... Failed. Deal with it and:
Thread.currentThread().interrupt();
}

Related

How to test code that subscribes to an Uni?

I know that I can test a method that returns an Uni:
#Test
public void testUni() {
service.doSomething().invoke(data -> {
// run assertions
}).subscribe().withSubscriber(UniAssertSubscriber.create()).assertCompleted();
}
But what if I want to test the method that subscribes to the Uni itself? For example, consider this piece of code:
public void execute() {
service.reprocessAll().subscribe().with(
success -> log.info("Reprocessing ran successfully."),
error -> log.severe("Reprocessing failed: " + error.getMessage())
);
}
If I try to test it like this...
#Test
public void shouldLogSuccessAfterReprocessing() {
service.execute()
Mockito.verify(log, times(1)).success("Reprocessing ran successfully");
}
The test will fail due to a race condition. I mean, the test code will run before the actual code under test (the log.success call). So how can I tell the test to wait for the Uni to complete? Or how could I refactor this to make it testable?
The proper question would be how to design the code so that it is unit-testable which may lead a different answer than the one I will be writing here to respond to your current need.
Since the service#reprocessAll computation will be triggered on the background, and you have no means of controlling it behavior as your #service method simply returns void, you can block the calling unit runtime thread awaiting for the processing to finish:
#Test
public void shouldLogSuccessAfterReprocessing() throws Exception {
service.execute()
Thread.sleep(1000); // wait for reprocessAll to finish then proceed with assertions
Mockito.verify(log, times(1)).success("Reprocessing ran successfully");
}
For finer control, you can use the awaitiliy library for condition testing.

How to use MockedStatic verify on static methods?

I have the following mocks for 2 different static method; UnitConversion.isCompatible() and Logging.error() that are called in my service method.
Here is my test method:
myService.demoMethod();
try (MockedStatic<UnitConversion> unitConversion= mockStatic(UnitConversion.class)) {
unitConversion.verify(never(), () -> UnitConversion.isCompatible(any()));
UnitConversion.isUnitsCompatible(any());
}
try (MockedStatic<Logging> logging = mockStatic(Logging.class)) {
logging.verify(times(1), () -> Logging.error(any()));
Logging.error(any();
}
The first method is never called while the second one is called one time when I debug. It is ok, but the test gives "Wanted but not invoked" error for the second method. I am not sure if I should call the static methods in try blocks, because I already call my service method that calls the static methods.
So, how can I verify the static method calls using MockedStatic (not powermock, etc)? SHould I call them in try blocks?
Update: I use the following approach, but it still gives "Wanted but not invoked" error even if breakpoint hit once to the static method called from the service method.
// I also try to call the service method under the test here again
demoService.create(request);
try (MockedStatic<LoggingUtils> mock = mockStatic(LoggingUtils.class)) {
// as the static method is void, no need to stub and not use "when()" in here
// I call the service method under the test
demoService.create(request);
// verify that the method is being invoked
mock.verify(times(1), () -> LoggingUtils.error(any(), any()));
}
Update-II:
demoService:
public CommandDTO create(final PurchaseRequest request) {
// code omitted
addLog();
return CommandDTO.builder().uuid(purchase.getUuid()).build();
}
private void addLog() {
LoggingUtils.error("error", null);
}
LoggingUtils:
public class LoggingUtils {
public static void error(String var1, Throwable var2) {
log.error(getString(var1), var2);
}
}
I can see a few issues in this snippet:
try (MockedStatic<UnitConversion> unitConversionMockStatic = mockStatic(UnitConversion.class)) {
unitConversionMockStatic.verify(never(), () -> UnitConversion.isCompatible(any()));
UnitConversion.isUnitsCompatible(any());
}
you verify that the method is being called before calling it
as you specified that you expect never(), this passes
you call the method with the argument matcher. This is illegal - you need to call with normal parameter.
Thus, the structure of the test should be
try (MockedStatic<UnitConversion> unitConversionMockStatic = mockStatic(UnitConversion.class)) {
// if needed, stub the static method with when
// call the static method (probably indirectly, via service under thest)
UnitConversion.isUnitsCompatible(10);
// verify that the method is being invoked
unitConversionMockStatic.verify(times(1), () -> UnitConversion.isCompatible(any()));
}
Note the usage of try-with-resources, MockStatic is no longer in effect when it is closed (which happens when you exit from the try-with-resources block). Thus, you must invoke the method under test (which calls the static method) inside of the try-with-resources block.

Iam getting Error like Unfinished Stubbing Detected in Mockito , Iam using Mockito for mocking

I am getting following exception while running the tests. I am using Mockito for mocking. The hints mentioned by Mockito library are not helping.
E.g. thenReturn() may be missing.
Examples of correct stubbing:
when(mock.isOk()).thenReturn(true);
when(mock.isOk()).thenThrow(exception);
doThrow(exception).when(mock).someVoidMethod();
Hints:
1. missing thenReturn()
2. you are trying to stub a final method, you naughty developer!
Here is my method:
From ps.setString I am unable to do code coverage. Can anyone help me?
public class Dao{
public int[][] batchInsertAll(Collection<UploadRequest> request, int batchSize, final String jobId) {
int[][] updateAllCounts = jdbcTemplate.batchUpdate("insert into tb_import(id,name) values("","")", request, batchSize,
new ParameterizedPreparedStatementSetter<UploadRequest>() {
public void setValues(PreparedStatement ps, UploadRequest argument) throws SQLException {
ps.setString(1, Id);
ps.setString(2, argument.getName());
}}); return updateAllCounts
}
}
Here is my test code:
#Test
public void batchInsertAll() {
int batchSize = 1000;
String jobId = "xyz";
List<UploadRequest> fileData = new ArrayList<UploadRequest>();
UploadRequest rowdata1 = new UploadRequest("1", "xyz");
UploadRequest rowdata1 = new UploadRequest("1", "abc");
fileData.add(rowdata1);
fileData.add(rowdata2);
int[][] updateAllCounts = new int[][] { { 1, 2 }, { 3, 4 } };
try {
Mockito.doAnswer(new Answer() {
public Object answer(InvocationOnMock invocation) {
PreparedStatement ps = Mockito.mock(PreparedStatement.class);
ParameterizedPreparedStatementSetter bpss = invocation.getArgumentAt(1,
ParameterizedPreparedStatementSetter.class);
try {
bpss.setValues(ps, 1);
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return updateAllCounts;
}
}).when(jdbcTemplate).batchUpdate(anyString(), fileData, 1000,
any(ParameterizedPreparedStatementSetter.class));
} catch (Exception e) {
assert (true);
}
mockDao.batchInsertAll(fileData, 1000, jobId);
}
First you have to think - what is your goal here?
You wrote a class Dao and a method batchInsertAll. I would think you'd want to test that. If you want to test that though you need to actually call that method. Calling
mockDao.batchInsertAll(fileData, 1000, jobId);
makes it look, like you're just calling a mock you created to test it, which obviously will do nothing except do whatever you configured that mock to do.
Also, the catching of Exception with assert(true) will not do what you think it'll do - this is a base Java assertion used for sanity checks in non-production builds. It will either not be run at all (as might be default behaviour when running an application without appropriate flag to enable them) or do nothing (since true is true, so it passes). It will not end the test with a positive result, it will not tell you it happened, it doesn't even count as test assertion. You might want to add some logging there, as without knowing an exception you didn't expect was thrown any number of shenanigans can slip by. Or even better, don't catch exceptions in tests. If unexpected exceptions get thrown you want the test to fail anyway right?
As to your direct problem it's hard to tell for sure without seeing the entire test class (I can see three mocks in your code - jdbcTemplate, mockDao and ps, only one of which is initialized as a Mock in the code you've given us, you only stub jdbcTemplate and from what I can tell without running the code it looks correct). Either the problem is somewhere you haven't shown us, or exception is thrown during stubbing of jdbcTemplate, causing that to not finish and fail leaving mock in invalid state.
Also worth noting, most of your code in doAnswer method is irrelevant. Even if you call real batchInsertAll that in turn will call jdbcTemplate.batchUpdate with some parameters, and your mock will return updateAllCounts array. doAnswer() line of methods is useful only if you need to change what your mock returns based on input arguments, otherwise you do some useless calculations you could have done wrong and end up with same result as .thenReturn(updateAllCounts) would.

In JUnit with Mockito, how can I wait for an asynchronous method to complete?

I am writing an integration test against some code that asynchronously creates a record when a different value is updated in the database. I would like to check the state of the system after the record is created, verifying that it was created as expected. The test therefore needs to wait until the record is created.
I can use Mockito to create a spy for the function that creates the record. Mockito even has the option to wait for the method to be called via Mockito.timeout, giving up if a certain amount of time has elapsed without the method being called:
// Use or create/wire in spy. In my case, this is set up with #SpyBean from spring-boot-test.
RecordCreationService recordCreationServiceSpy = ...;
testClass.update(someValue);
Mockito.verify(recordCreationServiceSpy, Mockito.timeout(10_000)).createRecord(ArgumentMatchers.any());
However, this merely waits for the call to have started, not for it to have been completed. Thus, this enters a race condition where the verification can finish before the desired call completes.
How can I cleanly and simply wait for the completion of a process before verifying in JUnit with Mockito?
This functionality doesn't directly exist in Mockito, as there is currently an open issue to add this functionality to Mockito (Mockito issue #1089).
The solution I am currently using is to write a custom answer for the spied method that waits for the call to be completed before returning. I then verify the result normally afterward.
#SpyBean
private RecordCreationService recordCreationServiceSpy;
#Test(timeout = 10_000)
public void recordShouldBeCreatedWhenDataIsUpdated() {
// Set up test here
updateValueAndWait(value);
assertEquals(1, recordRepository.findAll().size());
// Perform any additional verifications
}
private void updateValueAndWait(String value) {
CountDownLatch latch = new CountDownLatch(1);
Mockito.doAnswer(invocation -> {
Object result = invocation.callRealMethod();
latch.countDown();
return result;
}).when(recordCreationServiceSpy).insertRecord(any());
testClass.update(value);
try {
latch.await();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}

JUnit/Mockito test failing for bizarre reason

I have a very simple method that I am trying to unit test:
public class MyAntTask extends org.apache.tools.ant.Task {
public void execute() {
fire();
}
public void fire() {
// Do stuff
}
}
I just want to write a unit test that confirms that calling execute() always invokes fire(), so I wrote this:
#Test
public void executeCallsFire() {
//GIVEN
MyAntTask myTask = Mockito.mock(MyAntTask.class);
// Configure the mock to throw an exception if the fire() method
// is called.
Mockito.doThrow(new RuntimeException("fired")).when(myTask).fire();
// WHEN
try {
// Execute the execute() method.
myTask.execute();
// We should never get here; HOWEVER this is the fail() that's
// being executed by JUnit and causing the test to fail.
Assert.fail();
}
catch(Exception exc) {
// THEN
// The fire() method should have been called.
if(!exc.getMessage().equals("fired"))
Assert.fail();
}
}
I guess (and I'm by no means an expert) Mockito normally can't mock methods that return void, but this is a workaround. You basically say "wrap my object with a Mock that will always return a specific RuntimeException whenever a particular method is about to get executed". So, instead of fire() actually executing, Mockito just sees that its about to execute and throws an exception instead. Execution verified? Check.
Instead of passing, it fails at the first Assert.fail() just below the call to myTask.execute().
For the life of me, I can't figure out why. Here's the first 10-or-so lines of the enormous stack trace JUnit is giving me for the fail:
java.lang.AssertionError
at org.junit.Assert.fail(Assert.java:92)
at org.junit.Assert.fail(Assert.java:100)
at net.myproj.ant.tasks.MyAntTaskUnitTest.executeCallsFire(MyAntTaskUnitTest.java:32)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:616)
Any thoughts here, ye Mockito Gurus of StackOverflow? Thanks in advance!
Because myTask is a mock, the real object isn't called at all. To call a real object, use a spy.
You can test that a method is called using verify so there's no need for the exceptions.
public void executeCallsFire() {
MyAntTask myTask = Mockito.spy(new MyAntTask());
myTask.execute();
Mockito.verify(myTask).fire();
}
Wanting to mock the object that you're testing doesn't seem right though. It's usually better to design the test so that you're verifying calls to a separate object instead.
I see here more design issue:
why do you need one line method and both of them are public?
the mocks are for simulating dependencies and not for the class under test
if you'll make fire (quite unclear name) as private. You shouldn't test private behavior of your class

Categories