Reputation: 173
I have a similar problem to this one: when trying to make an integration test on a controller which invokes an @Async
method from a service, an AssertionError: Async not started
occurs.
The guy suggests something that I don't clearly understand:
you have to wrap your response Callable or DeferredResult
That's my service method:
@Async
@Override
public Future<String> migrateMovies() {
Collection<MetadataItem> metadataMovies = metadataItemService.getAllByMetadataType(MOVIE_TYPE);
Collection<Movie> movies = mapMovies(metadataMovies);
movieService.saveMovies(movies);
return CompletableFuture.supplyAsync(() -> movies.size() + " movies migrated successfully!");
}
That's my controller method:
@PostMapping("/movies")
public ResponseEntity<String> migrateMovies() throws ExecutionException, InterruptedException {
return ResponseEntity.ok(movieMigrationService.migrateMovies().get());
}
And that's how I'm trying to test it:
@Test
@WithMockUser(username = "username")
void migrateMoviesSuccessfully() throws Exception {
Collection<Movie> expectedMovies = Lists.list(new Movie(), new Movie());
when(movieService.saveMovies(anyCollection())).thenReturn(expectedMovies);
Future<String> expectedResponse =
CompletableFuture.supplyAsync(() -> expectedMovies.size() + " movies migrated successfully!");
when(movieMigrationService.migrateMovies()).thenReturn(expectedResponse);
MvcResult mvcResult = mockMvc.perform(post("/movies"))
.andExpect(request().asyncStarted())
.andReturn();
mockMvc.perform(asyncDispatch(mvcResult))
.andExpect(status().isOk())
.andExpect(content().string("2 movies migrated successfully!"));
}
Could someone explain concretely for my example how this wrapping should happen?
I'm open to any other suggestions too!
NOTE: My application is properly running asynchronously + my unit tests for the service migrateMovies()
method are successful, it's only the integration test that is being stubborn :)
Upvotes: 0
Views: 4648
Reputation: 2250
I want to add a note to the OP answer that if the request mapping is wrong or the API does not exist, the same error will appear.
Upvotes: 3
Reputation: 173
I managed to solve my problem quite quickly after posting. I literally just wrapped the return type of my controller in a Callable + used a supplier for the return statement:
@PostMapping("/movies")
public Callable<ResponseEntity<String>> migrateMovies() throws ExecutionException, InterruptedException {
return () -> ResponseEntity.ok(movieMigrationService.migrateMovies().get());
}
No changes to the test!
Hope this can be helpful for somebody!
Upvotes: 2