Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Speed Up Spring MockMvc Integration Test with Embedded Cassandra

We are using MockMvc Framework to test Spring Controllers with JUnit. Controller returns a DefferedResult.

The mockmvc.perform looks like bellow

mockMvc.perform(post("/customer")
                .accept(APPLICATION_JSON)
                .header(AUTH_TOKEN_KEY, "xyz")
                .header(FROM_KEY, "[email protected]")
                .content(json)
                .contentType(APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(request().asyncStarted());

And it takes a lot of time. We are Using embedded cassandra and because of that it takes a lot of time.

I tried this as well, but it's same.

MvcResult mvcResult = mockMvc.perform(post("/customer")
            .accept(APPLICATION_JSON)
            .header(AUTH_TOKEN_KEY, "xyz")
            .header(FROM_KEY, "[email protected]")
            .content(json)
            .contentType(APPLICATION_JSON))
            .andReturn();

mockMvc.perform(asyncDispatch(mvcResult))
            .andExpect(status().isOk())
            .andExpect(request().asyncStarted());

I've hundreds of tests, because of which the build process is really slow.

Is there a way, using JUnit I can say perform the request and wait for response in another thread to assert the results, Or anyother good way of speeding it up.

Thanks

like image 380
Mritunjay Avatar asked Mar 21 '16 13:03

Mritunjay


People also ask

Is MockMvc thread safe?

From a technical point of view MockMvc is not thread-safe and shouldn't be reused.

Should integration tests use database?

Integration tests focus on testing how separate parts of the program work together. In the context of applications using a database, integration tests usually require a database to be available and contain data that is convenient to the scenarios intended to be tested.

Is MockMvc integration test?

Learn to use Spring MockMVC to perform integration testing of Spring webmvc controllers. MockMVC class is part of Spring MVC test framework which helps in testing the controllers explicitly starting a Servlet container.


2 Answers

Do you really need the Cassandra/Persistence-Layer of your application for this test?

If the anser is no, or if the answer is no a wide array of tests cases, than you could inject another persitsence repoitory when running tests. To achive this, you could use Spring's built in Profile functionality and annotate your tests accordingly, for example:

@RunWith(SpringJUnit4ClassRunner.class)
@ActiveProfile("StubPersistence")
public class WebLayerIntegrationTests {
...
}

You could then have a stubbed version of your Cassanda-Repository for your tests, that are allowed to work with static data:

@Profiles("StubPersistence")
@Repository
public class StubCassandaRepository {
    ...
}

This class could be backed by a simple data structure like a HashSet or similar, depdends on your use case. The possibility of this approach depdens heavy on your software architecture, so it might not be possible if you can't stub out your Cassandra depdencies.

I also wonder if you really need hundreds of test, that need your complete application, including the web layer. You can of course significantly speed up your tests by favoring Unit-Tests over Integration-Tests, so that you don't need to initiliaze the Spring-Context. Depends on your application and software architecture as well.

There will also be some testing improvements in Spring-Boot 1.4 that will allow you to specifically initilize single slices of your application for testing (like Persistence, or Web-Layer): https://spring.io/blog/2016/04/15/testing-improvements-in-spring-boot-1-4

So, my best advice is: If you want to test your Controllers, test only your Controllers and not your Persistence-Layer, stub it out instead. If you want to test your Persistence-Layer, start with the interfaces of your Persistence-Layer, don't use your Controllers as the test-interface.

like image 197
Kevin Wittek Avatar answered Nov 02 '22 18:11

Kevin Wittek


As I mentioned in my question We are Using embedded cassandra and because of that it takes a lot of time.

I tried looking things in cassandra.yaml file and changed the line below.

commitlog_sync_batch_window_in_ms: 90

to

commitlog_sync_batch_window_in_ms: 1

That's all and the build time was reduced from 30 minutes to 2 minutes.

From cassandra.yaml comments:-

It will wait up to commitlog_sync_batch_window_in_ms milliseconds for other writes, before performing the sync.

After reducing this time the wait time was reduced and build time got reduced.

like image 1
Mritunjay Avatar answered Nov 02 '22 17:11

Mritunjay