Skip to main content

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.

  1. POM - Configure jetty for deploying your app and running tests against it.
  2. .
    
    
     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
      
     
    
    .
    .
    
  3. MockBeanInjector.java - In order to test double database and service calls
  4. 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 ResponseEntity response = new ResponseEntity(HttpStatus.NO_CONTENT);
                when(mockAsGateway.callAuthorizeService("12345")).thenReturn(response);
                return mockAsGateway;
            } else {
                return bean;
            }
        }
    }
    
  5. Finally tests
  6. 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 HttpEntity httpEntity = 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

Popular posts from this blog

Installing i3lock-color on Ubuntu

i3lock is fancy lock screen for Linux. There is i3lock dep available on Ubuntu but its not what I was looking for; I was more interested in i3lock-color . Lets see how we can install the same on ubuntu. PS: I'm using Ubuntu 16.04 Get source code for i3lock-color $ git clone https://github.com/PandorasFox/i3lock-color.git  $ cd i3lock-color Install required packages to build i3lock  $ apt install libev-dev $ apt install libxcb-composite0 libxcb-composite0-dev libxcb-xinerama0 libxcb-randr0  $ apt install libxcb-xinerama0-dev  $ apt install libxcb-xkb-dev  $ apt install libxcb-image0-dev  $ apt install libxcb-util-dev $ apt install libxkbcommon-x11-dev $ apt install libjpeg-turbo8-dev  $ apt install libpam0g-dev Build  $ autoreconf -i && ./configure && make Execute $ ./lock.sh Assign Shortcut In order to assign shortcut, install compizconfig $ sudo apt-get install compizconfig-settings-manager compiz-plugins-extra and then go

INTO OUTFILE query, How to modify & output null values ?

I tried one query (originally asked at JR) on MySQL which export the table data into a file, with a comma delimited field. The query is straight forward and replace the null column value by "\N" character, but when I want to replace that "\N" value by some other character like "0" or simple empty field like " ", its gets little tricky. Here is the base query SELECT Id, name, age FROM student INTO OUTFILE 'c:/result.txt' FIELDS TERMINATED BY ',' OPTIONALLY ENCLOSED BY '"' LINES TERMINATED BY '\n'; And it outputs like, 1, "sagar", 23 2, "anant", 24 Now suppose some 'name' fields are null, then it outputs like 1, "sagar", 23 2, \N, 24 Now to obtain my desired results, which replace this null (\N) values by empty string like, "", I tried out two solutions --1. Using CASE statement SELECT Id, CASE WHEN name IS NULL THEN '' ELSE name END AS NewName, age FROM s

GlassFish V3 admin console taking too much time to load.

If you have installed Glassfish V3 and trying to load admin console, but after signing in, is it taking too much time to get to the main page ? Do you have server.log entry like this: admin console: initSessionAttributes() Cannot refresh Catalog : Connection timed out then its time to tweak some files. Here its how: 1. Update the %GLASSFISH_HOME/glassfish/domains/domain1/domain.xml -Dcom.sun.enterprise.tools.admingui.NO_NETWORK=true This will block up the News item, the registration item, etc 2. Remove update tool jar (Backup and remove this JAR) %GLASSFISH_HOME/glassfish/modules/console-updatecenter-plugin.jar Delete this dir: %GLASSFISH_HOME/glassfish/domains/domain1/osgi-cache %GLASSFISH_HOME/glassfish/domains/domain1/generated Now start the server (bin/asadmin start-domain) and you will see the admin console won't be hang up and take you directly to main page.