Mocking a Vertx.io async handler - java

when I was sync I wrote unit tests mocking the persistence part and check the caller's behavior. Here is an example about what I usually did:
#Mock
private OfferPersistenceServiceImpl persistenceService;
#Inject
#InjectMocks
private OfferServiceImpl offerService;
...
#Test
public void createInvalidOffer() {
offer = new Offer(null, null, null, null, null, 4, 200D, 90D);
String expectedMessage = Offer.class.getName() + " is not valid: " + offer.toString();
Mockito.when(persistenceService.create(offer)).thenThrow(new IllegalArgumentException(expectedMessage));
Response response = offerService.create(offer);
Mockito.verify(persistenceService, Mockito.times(1)).create(offer);
Assert.assertEquals(INVALID_INPUT, response.getStatus());
String actualMessage = response.getEntity().toString();
Assert.assertEquals(expectedMessage, actualMessage);
}
But now I fell in love with Vertx.io (to which I am pretty new) and I want to be async. Nice. But Vertx has handlers, so the new persistence component to mock looks like this:
...
mongoClient.insert(COLLECTION, offer, h-> {
...
});
So I am guessing how to mock handler h to tests class who's using that mongoClient or even if it is the right way to test with Vertx.io. I am using vertx.io 3.5.0, junit 4.12 and mockito 2.13.0. Thanks.
Update
I tried to follow tsegimond suggestion but I can't get how Mockito's Answer and ArgumentCaptor can help me. Here is what I tried so far.
Using ArgumentCaptor:
JsonObject offer = Mockito.mock(JsonObject.class);
Mockito.when(msg.body()).thenReturn(offer);
Mockito.doNothing().when(offerMongo).validate(offer);
RuntimeException rex = new RuntimeException("some message");
...
ArgumentCaptor<Handler<AsyncResult<String>>> handlerCaptor =
ArgumentCaptor.forClass(Handler.class);
ArgumentCaptor<AsyncResult<String>> asyncResultCaptor =
ArgumentCaptor.forClass(AsyncResult.class);
offerMongo.create(msg);
Mockito.verify(mongoClient,
Mockito.times(1)).insert(Mockito.anyString(), Mockito.any(), handlerCaptor.capture());
Mockito.verify(handlerCaptor.getValue(),
Mockito.times(1)).handle(asyncResultCaptor.capture());
Mockito.when(asyncResultCaptor.getValue().succeeded()).thenReturn(false);
Mockito.when(asyncResultCaptor.getValue().cause()).thenReturn(rex);
Assert.assertEquals(Json.encode(rex), msg.body().encode());
and using Answer:
ArgumentCaptor<AsyncResult<String>> handlerCaptor =
ArgumentCaptor.forClass(AsyncResult.class);
AsyncResult<String> result = Mockito.mock(AsyncResult.class);
Mockito.when(result.succeeded()).thenReturn(true);
Mockito.when(result.cause()).thenReturn(rex);
Mockito.doAnswer(new Answer<MongoClient>() {
#Override
public MongoClient answer(InvocationOnMock invocation) throws Throwable {
((Handler<AsyncResult<String>>)
invocation.getArguments()[2]).handle(handlerCaptor.capture());
return null;
}
}).when(mongoClient).insert(Mockito.anyString(), Mockito.any(),
Mockito.any());
userMongo.create(msg);
Assert.assertEquals(Json.encode(rex), msg.body().encode());
And now I got confused. Is there a way to mock an AsyncResult to let it return false on succeed()?

Finally I got some times to investigate and I made it. Here is my solution.
#RunWith(PowerMockRunner.class)
#PowerMockRunnerDelegate(VertxUnitRunner.class)
#PrepareForTest({ MongoClient.class })
public class PersistenceTest {
private MongoClient mongo;
private Vertx vertx;
#Before
public void initSingleTest(TestContext ctx) throws Exception {
vertx = Vertx.vertx();
mongo = Mockito.mock(MongoClient.class);
PowerMockito.mockStatic(MongoClient.class);
PowerMockito.when(MongoClient.createShared(Mockito.any(), Mockito.any())).thenReturn(mongo);
vertx.deployVerticle(Persistence.class, new DeploymentOptions(), ctx.asyncAssertSuccess());
}
#SuppressWarnings("unchecked")
#Test
public void loadSomeDocs(TestContext ctx) {
Doc expected = new Doc();
expected.setName("report");
expected.setPreview("loremipsum");
Message<JsonObject> msg = Mockito.mock(Message.class);
Mockito.when(msg.body()).thenReturn(JsonObject.mapFrom(expected));
JsonObject result = new JsonObject().put("name", "report").put("preview", "loremipsum");
AsyncResult<JsonObject> asyncResult = Mockito.mock(AsyncResult.class);
Mockito.when(asyncResult.succeeded()).thenReturn(true);
Mockito.when(asyncResult.result()).thenReturn(result);
Mockito.doAnswer(new Answer<AsyncResult<JsonObject>>() {
#Override
public AsyncResult<JsonObject> answer(InvocationOnMock arg0) throws Throwable {
((Handler<AsyncResult<JsonObject>>) arg0.getArgument(3)).handle(asyncResult);
return null;
}
}).when(mongo).findOne(Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any());
Async async = ctx.async();
vertx.eventBus().send("persistence", new JsonObject(), msgh -> {
if (msgh.failed()) {
System.out.println(msgh.cause().getMessage());
}
ctx.assertTrue(msgh.succeeded());
ctx.assertEquals(expected, Json.decodeValue(msgh.result().body().toString(), Doc.class));
async.complete();
});
async.await();
}
}
Use Powemockito to mock the MongoClient.createShared static method, so you'll have your mock when verticle starts. Mocking async handler is a bit of code to write. As you can see mocking start at Message<JsonObject> msg = Mockito.mock(Message.class); and ends at Mockito.doAnswer(new Answer.... In the Answer's method pick the handler param and force it to handle your async result then you're done.

Normally, I'd use a comment to post this, but formatting gets lost. The accepted solution is works great, just note that it can be simplified a bit using Java 8+, and you can use your actual objects instead of JSON.
doAnswer((Answer<AsyncResult<List<Sample>>>) arguments -> {
((Handler<AsyncResult<List<Sample>>>) arguments.getArgument(1)).handle(asyncResult);
return null;
}).when(sampleService).findSamplesBySampleFilter(any(), any());
getArgument(1), refers to the index of the handler argument in a method such as:
#Fluent
#Nonnull
SampleService findSamplesBySampleFilter(#Nonnull final SampleFilter sampleFilter,
#Nonnull final Handler<AsyncResult<List<Sample>>> resultHandler);

Related

vert.x testing with TestNg

i am new to vert.x , i am trying to make unit testing by calling my webservices .
i need an example of testing webservices with testng.
when i did it with junit5 it works fine with the below code
#BeforeMethod
private static void deploy_verticle(Vertx vertx , VertxTestContext testContext) {
vertx.deployVerticle(new MainVerticle(), testContext.completing());
}
#Test
public void getTestFalse(Vertx vertx , VertxTestContext testContext) throws InterruptedException {
Assert.assertTrue("3".contains("tesdfsdf"));
req = new HttpRequestEntityTest();
req.setHost("localhost");
req.setPort(8089);
req.setUri("/api/data");
utilTest = new RestUtilTest();
response = new HttpResponseEntityTest();
utilTest.getTestUtil(req, testContext.succeeding(response -> {
testContext.verify(() -> {
Assert.assertTrue(response.getBodyStr().contains("tesdfsdf"));
});
testContext.completeNow();
}));
}
#AfterMethod
public void finish(Vertx vertx , VertxTestContext testContext) {
context.getVertx().close(context.getTestContext().succeeding(response -> {
context.getTestContext().completeNow();
}));
}
but when i try to work with TestNg like this :
#SuppressWarnings("deprecation")
#Test
public void getTestIqvia() throws InterruptedException {
Future<HttpResponseEntityTest> future = Future.future();
response = new HttpResponseEntityTest();
req = new HttpRequestEntityTest();
req.setHost("localhost");
req.setPort(8089);
req.setUri("/api/data");
utilTest = new RestUtilTest();
utilTest.getTestUtil(req, response -> {
System.out.println(response.result().getBodyStr());
System.out.println(response.result().getBodyStr().contains("dsds"));
Assert.assertTrue(response.result().getBodyStr().contains("fdsfds"));
});
GetTestUtil Function :
public Future<HttpResponseEntityTest> getTestUtil(HttpRequestEntityTest req,
Handler<AsyncResult<HttpResponseEntityTest>> resultHandler) {
future = Future.future();
WebClient client = WebClient.create(vertx);
response = new HttpResponseEntityTest();
client.get(req.getPort(), req.getHost(), req.getUri()).send(ar -> {
if (ar.succeeded()) {
response.setStatusCode(ar.result().statusCode());
response.setBodyStr(ar.result().bodyAsString());
future.complete(response);
System.out.println("Received response with status code get" + response.getStatusCode());
resultHandler.handle(Future.succeededFuture(response));
} else {
response.setErrorMsg(ar.cause().getMessage());
System.out.println("Something went wrong " + ar.cause().getMessage());
future.complete(response);
}
});
return future;
}
always sending to web client not entered in the arrow function ar and always test success because it doesn't go to Assert function . except fewtimes in debugging mode only
can any one has ana example in testNG with Vert.x?? or what's wrong in my code?
This happens because the getTestIqvia completes before the WebClient callback is invoked.
With jUnit5, the corresponding Vert.x test extension makes sure the test is not marked as passed until all the asynchronous assertions pass.
With TestNG you need to do this manually. In practice, you need to make the test wait until the future returned by getTestUtil is completed.

How to test a method using a PrintWriter?

I have following method:
#Component
public class WriteCsvToResponse {
private static final Logger LOGGER = LoggerFactory.getLogger(WriteCsvToResponse.class);
public void writeStatus(PrintWriter writer, Status status) {
try {
ColumnPositionMappingStrategy mapStrategy
= new ColumnPositionMappingStrategy();
mapStrategy.setType(Status.class);
String[] columns = new String[]{"id", "storeId", "status"};
mapStrategy.setColumnMapping(columns);
StatefulBeanToCsv btcsv = new StatefulBeanToCsvBuilder(writer)
.withQuotechar(CSVWriter.NO_QUOTE_CHARACTER)
.withMappingStrategy(mapStrategy)
.withSeparator(',')
.build();
btcsv.write(status);
} catch (CsvException ex) {
LOGGER.error("Error mapping Bean to CSV", ex);
}
}
I have no idea how to test it properly using mockito.
Use it to wrap the object status into csv format.
I used StringWriter to wrap the response in it.
There are no more details left, but it seems I have to create some words to pass the validation :)
You do not need mockito to test this method, only a java.io.StringWriter.
Here is how you can write the test for a nominal use:
#Test
void status_written_in_csv_format() {
// Setup
WriteCsvToResponse objectUnderTest = new WriteCsvToResponse ();
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
// Given
Status status = ...
// When
objectUnderTest.writeStatus(printWriter, status);
// Then
String actualCsv = stringWriter.toString();
assertThat(actualCsv.split("\n"))
.as("Produced CSV")
.containsExactly(
"id,storeId,status",
"42,142,OK");
}
This example assume some things about your Status object, but you have the general idea.
For assertions, I use AssertJ, but you can do the same with JUnit5 built-in assertions.
Hope this helps !
With a bit of a refactoring, where the Builder is a Spring Bean injected into this component.
You can then mock that builder to return a mocked StatefulBeanToCsv, specifically the write method, where you write the conditions and assertions. If you encounter an error, you throw some unchecked exception, like IllegalStateException, if everything is alright, you don't throw anything
you can write a test like this and change your input in write method:
#Test
public void test() {
WriteCsvToResponse writeCsvToResponse = mock(WriteCsvToResponse.class);
doAnswer(new Answer() {
public Object answer(InvocationOnMock invocation) {
Object[] args = invocation.getArguments();
write((Status)args[1]);
return null;
}
}).when(writeCsvToResponse).writeStatus(any(PrintWriter.class),any(Status.class));
writeCsvToResponse.writeStatus(writer, status);
}
public void write(Status status) {
// do anythings you like with status
}

How can i unit test a method that contains vertx().eventBus().send()?

Frustrating. Everywhere i look, i see samples of testing async Vertx code, but nothing that comes close to what i am trying to test.
Vertx 3.3.2, JUnit 4.12, Java 8
The method under test sends a message to the event bus. I want to verify that what happens in the eventBus().send() response handler is happening.
Sooooooo many examples i see have the eventBus().send() method in the TEST ITSELF (thus, testing the other end of the event bus - the consumer) I want to test the response handler in the .send()
I have tried Async in the test. Tried ArgumentCaptor. Tried Thread.sleep(). Tried doAnswer(). Nothing seems to get the test to (a) wait for the async eventBus().send() call in the method under test to finish and (b) able to verify() that there was an interaction (i think this might have to do with the different between the Vertx.TestContext and the JUnit.Runner Context..)
Code:
Method under test:
public void sendToEventBusAddress(RoutingContext context, String requestId, String userId) {
List<String> stuff = split(context.request().getParam("stuffToSplit"));
JsonObject eventBusMessage = new JsonObject()
.put("requestId", requestId)
.put("stuffList", new JsonArray(stuff))
.put("userId", userId);
LOGGER.info("Putting message: {} onto the EventBus at address: {}", eventBusMessage.encodePrettily(), EventBusEndpointEnum.STUFF_ACCESS.getValue());
context.vertx().eventBus().send(EventBusEndpointEnum.STUFF_ACCESS.getValue(), eventBusMessage, new DeliveryOptions().setSendTimeout(timeout), async -> {
if (async.succeeded()) {
LOGGER.info("EventBus Response: {}", async.result().body().toString());
context.response().setStatusCode(HttpStatus.SC_OK);
context.response().headers().set(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN);
context.response().end(async.result().body().toString());
} else {
LOGGER.error(errorMessage);
context.response().setStatusCode(HttpStatus.SC_BAD_REQUEST);
context.response().end(errorMessage);
}
});
}
Simplified (non-working) Test case and class:
#RunWith(VertxUnitRunner.class)
public class MyBrokenTest {
#Mock private RoutingContext routingContext;
#Mock private HttpServerRequest contextRequest;
#Mock private HttpServerResponse contextResponse;
#Mock private MultiMap responseHeaders;
#Rule public RunTestOnContext rule = new RunTestOnContext();
#Before
public void setUp(TestContext context) {
MockitoAnnotations.initMocks(this);
}
#Test
public void testOne(TestContext context) {
when(routingContext.vertx()).thenReturn(rule.vertx());
when(routingContext.request()).thenReturn(contextRequest);
when(contextRequest.getParam("stuffToSplit")).thenReturn("04MA");
when(routingContext.response()).thenReturn(contextResponse);
when(contextResponse.headers()).thenReturn(responseHeaders);
rule.vertx().eventBus().consumer(EventBusEndpointEnum.STUFF_ACCESS.getValue(), res -> {
res.reply("yo");
});
ClassUnderTest cut= new ClassUnderTest(180000);
cut.sendToEventBusAddress(routingContext, "testRequestId", "UnitTestId");
verify(contextResponse).setStatusCode(200);
}
}
I know that the test in its current form won't work, because the method under test returns as soon as the eventBus().send() method is called inside the method, and therefore, the verify fails with 'no interactions'.
What i can't figure out, is how to verify it properly given the async nature of Vertx!
Thanks
I did it so:
At #BeforeAll annotated method I deploy only the sending verticle.
At #BeforeEach - I create a consumer for the given message and store message(s) to variable/collection
Something like:
receivedMessage = new Message[1];
eventBus.consumer("DB",
message -> {
message.reply("OK");
receivedMessage[0] = message;
});
context.completeNow();
In test I validate stored value(s):
client.get(8080, "localhost", "/user/" + id)
.as(BodyCodec.string())
.send(context.succeeding((response -> context.verify(() -> {
Assertions.assertEquals(expectedMessage, receivedMessage[0].body());
context.completeNow();
}))));

Unitest Create(Post) method using mockito

Given a class SchedulerResource which has the following createSchedules method and a bunch of constants used in the method, how can I use mockito to write a unit-test for the createSchedules method?
#PostMapping
public ResponseEntity<CustomResponse> createScheduler(#Valid #RequestBody SchedulerDTO schedulerDTO) {
if(schedulerDTO != null)
{
schedulerService.saveScheduler(schedulerDTO);
customResponse.setMessage("Schedule has been created!");
return new ResponseEntity<>(customResponse ,HttpStatus.OK);
} else {
customResponse.setMessage("Not Create!");
return new ResponseEntity<>(customResponse,HttpStatus.NOT_FOUND);
}
}
Test class:
#Test
public void createScheduler_Success() throws Exception {
SchedulerDTO scheduler = new SchedulerDTO();
Long sId = new Long(2);
scheduler.setSchedulerId(sId);
scheduler.setLinearChannelId((long)1);
scheduler.setDurationMs((long) 5000);
scheduler.setStatus(StatusEnum.NEW);
scheduler.setStartTime("2018-03-01T05:55:25");
scheduler.setEndTime("2018-03-01T05:57:25");
when(schedulerService.saveScheduler(scheduler)).thenReturn(scheduler);
mockMvc.perform(post("/linear/api/1.0/schedules")
.contentType(MediaType.APPLICATION_JSON)
.content(asJsonString(scheduler)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.message", is("Schedule has been created!")));
}
So is ok with :
if(schedulerDTO != null)
{
schedulerService.saveScheduler(schedulerDTO);
customResponse.setMessage("Schedule has been created!");
return new ResponseEntity<>(customResponse ,HttpStatus.OK);
}
But what about:
else{
customResponse.setMessage("Not Create!");
return new ResponseEntity<>(customResponse,HttpStatus.NOT_FOUND);
}
So, - how can I write for the case where schedulerDTO == null?
Simple: you pass in null, and then you put down different specs for your mockMvc object, such as andExpect(status().isNotFound() (or something alike).
Beyond that, you can use methods like verifyZeroInteractions() to ensure no calls went to that mocked service object for example.
In that sense, it really isn't much different from testing the other case: you step back, and look at all the things that happen in the else branch, and then you think of ways how to observe/verify them.

Testing Pull Subscription in Java EWS API using PowerMockito

I have a function that processes events obtained by a PullSubscription to Microsoft Exchange.
public void processEvents(ExchangeService service, PullSubscription subscription)
throws Exception {
GetEventsResults events = subscription.getEvents();
// Loop through all item-related events.
for (ItemEvent itemEvent : events.getItemEvents()) {
if (itemEvent.getEventType() == EventType.NewMail) {
EmailMessage message = EmailMessage.bind(service, itemEvent.getItemId());
EmailParser emailParser = new EmailParser();
emailParser.parse(message, service);
}
}
}
I am trying to test it using PowerMockito because ExchangeService is a final class.
So I have mocked ExchangeService and PullSubscription as follows:
ExchangeService serviceMock = PowerMockito.mock(ExchangeService.class);
PullSubscription subscriptionMock = PowerMockito.mock(PullSubscription.class);
#Test
public void startPullNotification() throws Exception {
ProcessEmails pr = new ProcessEmails("config.properties");
pr.startPullNotification(serviceMock);
}
When I'm trying to test it using the following code it throws a NullPointerException because subscription.getEvents() returns null (i.e. the subscriptionMock has no events in it).
I tried stubbing it by mocking the eventResults that has to be returned:
when(subscriptionMock.getEvents()).thenReturn(eventResultsMock);
It doesn't work since the getEvents() is not called in the test function. I wanted to know how to test this function?
http://archive.msdn.microsoft.com/ewsjavaapi
Solution:
I had to mock every object being created in the function.
Also, I had to add the following above the class declaration.
#RunWith(PowerMockRunner.class)
#PrepareForTest({ ClassBeingTested.class })

Categories

Resources