Writing fast & maintainable integration tests using test double, in-memory db, jetty, maven and spring
Writing an integration test which test end to end flow of your application can become cumbersome activity if you really hitting real db and services. The best way to mock, test double your external dependencies and thus speed up your test execution.
I created a dummy map-service project which demonstrate about writing maintainable and speedy integration tests using mocking, test double pattern, spring and automating them using maven and jetty. You can find the project at my github location: https://github.com/sagarr/maps-service
Here are some code snippets explaining the important steps in configuring your project.
- POM - Configure jetty for deploying your app and running tests against it.
- MockBeanInjector.java - In order to test double database and service calls
- Finally tests
.org.mortbay.jetty jetty-maven-plugin ${jettyVersion} /${project.artifactId} 8005 STOP 5 true 8080 60000 start-jetty pre-integration-test run 0 true stop-jetty post-integration-test stop . . maven-failsafe-plugin 2.12 **/integration/**Test.java integration-test
public class MockBeanInjector implements BeanPostProcessor { private final static Logger LOG = LoggerFactory.getLogger(MockBeanInjector.class); @Override public Object postProcessBeforeInitialization(final Object bean, final String beanName) throws BeansException { return bean; } @Override public Object postProcessAfterInitialization(final Object bean, final String beanName) throws BeansException { if (bean instanceof DataSource) { LOG.info("Mocking DataSource instance: " + bean); final EmbeddedDatabaseBuilder embeddedDatabaseBuilder = new EmbeddedDatabaseBuilder(); final EmbeddedDatabase embeddedDatabase = embeddedDatabaseBuilder.addScript("schema.sql").addScript("data.sql").build(); return embeddedDatabase; // else // return new ClassPathXmlApplicationContext("applicationContext-test.xml").getBean("dataSource"); } if (bean instanceof AuthserverGateway) { LOG.info("Mocking AuthserverGateway instance: " + bean); final AuthserverGateway mockAsGateway = mock(AuthserverGateway.class); final ResponseEntityresponse = new ResponseEntity (HttpStatus.NO_CONTENT); when(mockAsGateway.callAuthorizeService("12345")).thenReturn(response); return mockAsGateway; } else { return bean; } } }
public class PoiWsRestClientTest { @Test public void should_create_poi() { // given final Poi poi = new Poi(); poi.setName("Pizza Center"); poi.setLatitude(new BigDecimal("23.23212")); poi.setLongitude(new BigDecimal("34.231312")); // when final URI location = new RestTemplate().postForLocation("http://localhost:8080/maps-service/pois", poi); // then assertThat(location.getPath(), endsWith("/pois/102")); } @Test public void should_read_poi() { // when final Poi poi = new RestTemplate().getForObject("http://localhost:8080/maps-service/pois/100", Poi.class); // then assertThat(poi.getId(), is("100")); } @Test public void should_delete_poi() { // given final HttpHeaders headers = new HttpHeaders(); headers.set("Authorization", "12345"); final HttpEntityhttpEntity = new HttpEntity (headers); // when final ResponseEntity response = new RestTemplate().exchange("http://localhost:8080/maps-service/pois/101", HttpMethod.DELETE, httpEntity, String.class); // then assertThat(response.getStatusCode(), is(HttpStatus.NO_CONTENT)); } }
Comments