mockito and multiple HTTP in Spring Boot test - java

I'm having a big problem with a project that I'm working on and I'm wondering if you could help me.
I have to perform a few unit tests using mockito, all methods go great! until you have 2 calls to http in the same method and I don't know how to differentiate them.
I have the following on the tests:
// -----------------------------------------------------------services
#InjectMocks
private SandboxAccountService accountService;
#InjectMocks
private SandboxBalancesService balancesService;
#InjectMocks
private SandboxMovementsService movementService;
#Mock
private RestTemplate restTemplate;
#Mock
private RestTemplate restTemplateMovimientos;
#Test
public void test_movementsServiceImpl() throws Exception {
//LLAMADA A LISTA DE Account
List<Account> accountList = new ArrayList<>();
accountList.add(account);
accountList.add(account2);
ResponseEntity<List<Account>> list = new ResponseEntity<List<Account>>(accountList, HttpStatus.OK);
// FIRST HTTP CALL
when(restTemplate.exchange(anyString() , any(HttpMethod.class),
any(HttpEntity.class), any(ParameterizedTypeReference.class))).thenReturn(list);
//LLAMADA A LISTA DE MOVIMIENTOS
listMovent.add(movement);
listMovent.add(movementDos);
ResponseEntity<List<Movement>> listaMovi = new ResponseEntity<List<Movement>>(listMovent, HttpStatus.OK);
// Second HTTP CALL
when(restTemplateMovimientos.exchange(anyString() , any(HttpMethod.class),
any(HttpEntity.class), any(ParameterizedTypeReference.class))).thenReturn(listaMovi);
try {
AccountsMovementsResponse accountsMovementsResponse = movementService.getMovements(accountsMovementsRequest,
AUTORIZATHION_TOKEN, language);
} catch (Exception e) {
}
}
When debug does the lists for me correctly and all well but when he switches to the service
//// This its a primary http ( Account)
ResponseEntity<List<Account>> exchange = restTemplate.exchange(sandboxAccountURL + userId, HttpMethod.GET,entity,
new ParameterizedTypeReference<List<Account>>() {
});
// This list its Account CORRECT
List<Account> lista=exchange.getBody();
// code.....
// This its a second http ( movement )
ResponseEntity<List<Movement>> movementList = restTemplate.exchange(GenerateUrl, HttpMethod.GET,entity,
new ParameterizedTypeReference<List<Movement>>() {
});
// This list should be moves, but it's a list of accounts.
List<Movement> listMovement= movementList.getBody();
My big problem is that instead of having 2 different lists I have 2 lists of them so the test can't continue.
if i try the code everything works without a problem and makes it work, the problem i have is that at the moment of testing it clones the lists.
I don't know if there is a way to make the mock's "when" can make them different because it makes me understand that it takes the first when I do.
Thank you very much for your help!

I found the solution, instead of using the key several times using the when you can make a single call and then making several returns in the order that you require attached the answer of how I work
when(restTemplate.exchange(anyString(), any(HttpMethod.class),
any(HttpEntity.class), any(ParameterizedTypeReference.class))).thenReturn(list).thenReturn(listaMovi);

Related

How to ignore a method call inside a method that is being tested?

I am trying to make a test pass with mockmvc and it is failing with the following error message:
Caused by: org.apache.kafka.common.config.ConfigException
We have Kafka in our service layer as a dependency, and it is being called inside the method we are testing.
Is there a way to ignore that specific call during tests?
In the example below, we want to ignore the notifyHrcOfInfectedUser() during testing.
public UserDto changeInfectionStatus(String deviceId) {
User user = this.userRepository.findById(deviceId)
.orElseThrow(() -> new EntityNotFoundException("Could not find user with id " + deviceId));
if (!hasPassedTwoWeeksMinimumRecoveryTime(user))
throw new InfectionStatusException("Unable to change infection status since it has not been at least" +
" two weeks since the last change.");
UserDto updatedUser = updateStatus(user).convertToDto();
notifyHrcOfInfectedUser(updatedUser.isInfected(), deviceId); // <-- Ignore this call during tests
return updatedUser;
}
private void notifyHrcOfInfectedUser(boolean isInfected, String deviceId) {
if (isInfected)
kafkaSender.publish("infection-contact", deviceId);
}
Are you able to mock the kafkaSender object? Then we can do something like...
final KafkaSender mockKafkaSender = Mockito.mock(KafkaSender.class);
Mockito.doNothing().when(mockKafkaSender).publish(any(),any());
Update...
Or to be more accurate
Mockito.doNothing().when(mockKafkaSender).publish(eq("infection-contact"),eq(expectedDeviceId));

Play! Framework Functional Test ghost data

Hoping someone else is having the same issue as me, or has other ideas.
I'm currently running Play 1.4.x (not by choice), but also working on upgrading to play 1.5.x, though I verified the same issue happens on both versions.
I created a simple Functional Test that loads data via fixtures
My fixture for loading test data is like so
data.yml
User(testUser):
name: blah
AccessToken(accessToken):
user: testUser
token: foo
Data(testData):
user: testUser
...
I've created a controller to do something with the data like this, that has middleware for authentication check. The routes file will map something like /foo to BasicController.test
public class BasicController extends Controller{
#Before
public void doAuth(){
String token = "foo"; // Get token somehow from header
AccessToken token = AccessToken.find("token = ?", token).first(); // returns null;
// do something with the token
if(token == null){
//return 401
}
//continue to test()
}
public void test(){
User user = //assured to be logged-in user
... // other stuff not important
}
}
Finally I have my functional test like so:
public class BasicControllerTest extends FunctionalTest{
#org.junit.Before
public void loadFixtures(){
Fixtures.loadModels("data.yml");
}
#Test
public void doTest(){
Http.Request request = newRequest()
request.headers.put(...); // Add auth token to header
Http.Response response = GET(request, "/foo");
assertIsOk(response);
}
}
Now, the problem I'm running into, is that I can verify the token is still visible in the headers, but running AccessToken token = AccessToken.find("token = ?", token).first(); returns null
I verified in the functional test, before calling the GET method that the accessToken and user were created successfully from loading the fixtures. I can see the data in my, H2 in-memory database, through plays new DBBrowser Plugin in 1.5.x. But for some reason the data is not returned in the controller method.
Things I've tried
Ensuring that the fixtures are loaded only once so there is no race condition where data is cleared while reading it.
Using multiple ways of querying the database via nativeQuery jpql/hql query language and through plays native way of querying data.
Testing on different versions of play
Any help would be very much appreciated!
This issue happens on functional tests, because JPA transactions must be encapsulated in a job to ensure that the result of the transaction is visible in your method. Otherwise, since the whole functional test is run inside a transaction, the result will only visible at the end of the test (see how to setup database/fixture for functional tests in playframework for a similar case).
So you may try this:
#Test
public void doTest() {
...
AccessToken token = new Job<AccessToken>() {
#Override
public User doJobWithResult() throws Exception {
return AccessToken.find("token = ?", tokenId).first();
}
}.now().get();
....
}
Hoping it works !
I think I had a similar issue, maybe this helps someone.
There is one transaction for the functional test and a different transaction for the controller. Changes made in the test will only become visible by any further transaction if those changes were committed.
One can achieve this by closing and re-opening the transaction in the functional test like so.
// Load / Persist date here
JPA.em().getTransaction().commit(); // commit and close the transaction
JPA.em().getTransaction().begin(); // reopen (if you need it)
Now the data should be returned in the controller method.
So your test would look like this:
public class BasicControllerTest extends FunctionalTest{
#org.junit.Before
public void loadFixtures(){
Fixtures.loadModels("data.yml");
JPA.em().getTransaction().commit();
// JPA.em().getTransaction().begin(); reopen (if you need it)
}
#Test
public void doTest(){
Http.Request request = newRequest()
request.headers.put(...); // Add auth token to header
Http.Response response = GET(request, "/foo");
assertIsOk(response);
}
}
I did never try this with fixtures. But i would assume they run in the same transaction.

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();
}))));

hystrix javanica collapser did not work

I am using hystrix javanica collapser in spring boot, but I found it did not work, my code just like this below:
service class:
public class TestService {
#HystrixCollapser(batchMethod = "getStrList")
public Future<String> getStr(String id) {
System.out.println("single");
return null;
}
#HystrixCommand
public List<String> getStrList(List<String> ids) {
System.out.println("batch,size=" + ids.size());
List<String> strList = Lists.newArrayList();
ids.forEach(id -> strList.add("test"));
return strList;
}
}
where I use:
public static void main(String[] args) {
TestService testService = new TestService();
HystrixRequestContext context = HystrixRequestContext.initializeContext();
Future<String> f1= testService.getStr("111");
Future<String> f2= testService.getStr("222");
try {
Thread.sleep(3000);
System.out.println(f1.get()); // nothing printed
System.out.println(f2.get()); // nothing printed
} catch (Exception e) {
}
context.shutdown();
}
It printed 3 single instead of 1 batch.
I want to know what's wrong with my code, a valid example is better.
I can't find a hystrix javanica sample on the internet, So I have to read the source code to solve this problem, now it's solved, and this is my summary:
when you use hystrix(javanica) collapser in spring-boot, you have to:
Defined a hystrixAspect spring bean and import hystrix-strategy.xml;
Annotate single method with #Hystrix Collapser annotate batch method with #HystrixCommand;
Make your single method need 1 parameter(ArgType) return Future , batch method need List return List and make sure size of args be equal to size of return.
Set hystrix properties batchMethod, scope, if you want to collapse requests from multiple user threads, you must set the scope to GLOBAL;
Before you submit a single request, you must init the hystrix context with HystrixRequestContext.initializeContext(), and shutdown the context when your request finish;

Unit testing a Restlet extractor

I'm looking for some guidance on real unit testing for Restlet components, and specifically extractors. There is plenty of advice on running JUnit to rest entire endpoints, but being picky this is not unit testing, but integration testing. I really don't want to have set up an entire routing system and Spring just to check an extractor against a mock data repository.
The extractor looks like this:
public class CaseQueryExtractor extends Extractor {
protected int beforeHandle(Request request, Response response) {
extractFromQuery("offset", "offset", true);
extractFromQuery("limit", "limit", true);
// Stuff happens...
attributes.put("query", query);
return CONTINUE;
}
}
I'm thinking part of the virtue of Restlets is that its nice routing model ought to make unit testing easy, but I can't figure out what I need to do to actually exercise extractFromQuery and its friends, and all my logic that builds a query object, without mocking so much that I'm losing testing against a realistic web request.
And yes, I am using Spring, but I don't want to have to set the whole context for this -- I'm not integration testing as I haven't actually finished the app yet. I'm happy to inject manually, once I know what I need to make to get this method called.
Here's where I'm at now:
public class CaseQueryExtractorTest {
private class TraceRestlet extends Restlet {
// Does snothing, but prevents warning shouts
}
private CaseQueryExtractor extractor;
#Before
public void initialize() {
Restlet mock = new TraceRestlet();
extractor = new CaseQueryExtractor();
extractor.setNext(mock);
}
#Test
public void testBasicExtraction() {
Reference reference = new Reference();
reference.addQueryParameter("offset", "5");
reference.addQueryParameter("limit", "3");
Request request = new Request(Method.GET, reference);
Response response = extractor.handle(request);
extractor.handle(request, response);
CaseQuery query = (CaseQuery) request.getAttributes().get("query");
assertNotNull(query);
}
}
Which of course fails, as whatever set up I am doing isn't enough to make Restlets able to extract the query parameters.
Any thoughts or pointers?
There is a test module in Restlet that can provide you some hints about unit testing. See https://github.com/restlet/restlet-framework-java/tree/master/modules/org.restlet.test/src/org/restlet/test.
You can have a look at class HeaderTestCase (see https://github.com/restlet/restlet-framework-java/blob/master/modules/org.restlet.test/src/org/restlet/test/HeaderTestCase.java).
For information, if you use attributes from request, your unit test will pass ;-) See below:
public class CaseQueryExtractor extends Extractor {
protected int beforeHandle(Request request, Response response) {
extractFromQuery("offset", "offset", true);
extractFromQuery("limit", "limit", true);
// Stuff happens...
CaseQuery query = new CaseQuery();
Map<String,Object> attributes = request.getAttributes();
attributes.put("query", query);
return CONTINUE;
}
}
I don't know if you want to go further...
Hope it helps you,
Thierry

Categories

Resources