Again writing fast & maintainable integration tests using in-memory db, liquibase, gradle and spring mvc test
This blog is improvisation to previously blogged testing effectively with database blog. In this blog we will remove the jetty setup and instead
use Spring MVC Test framework which kind of simulate the request/response for your controllers via Spring Web Application context (no deployment, to http client tests)
Here, we will write Spring MVC tests and -
- Create the HSQLDB in-memory instance (instantiating datasource instance)
- and run Liquibase scripts against them. (using Spring Lqiuibase bean)
Write usual Controller->Service->Repository layer.
@Controller
@RequestMapping("/reports")
public class MapAnomalyReportEndpoint {
@Autowired
private MapAnomalyReportService reportService;
@ResponseBody
@RequestMapping(method = RequestMethod.GET)
public Collection getReports() {
return reportService.getReports();
}
}
2. Create Spring Java Config (No XML)
Configure the controllers.
@Configuration
@EnableWebMvc
@Import(JdbcConfig.class)
@ComponentScan(basePackages = "com.rohankar.playground")
public class WebConfig {
@Bean
public InternalResourceViewResolver viewResolver() {
final InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/view/");
resolver.setSuffix(".jsp");
return resolver;
}
}
Configure the data source. I'm taking JDBC parameters from context, you can very well read them from .properties or system prop.
@Configuration
public class JdbcConfig {
@Autowired
private Environment env;
@Bean(destroyMethod = "close")
public DataSource getDataSource() throws NamingException {
final Context ctx = new InitialContext();
final BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName((String)ctx.lookup("java:comp/env/report/db/driverClass"));
ds.setUrl((String)ctx.lookup("java:comp/env/report/db/url"));
ds.setUsername((String)ctx.lookup("java:comp/env/report/db/user"));
ds.setPassword((String)ctx.lookup("java:comp/env/report/db/password"));
return ds;
}
@Bean
public JdbcTemplate getJdbcTemplate() throws NamingException {
return new JdbcTemplate(getDataSource());
}
}
3. Create Spring Java Config for tests
This config is purely for running liquibase scripts on datasource.
@Configuration
@Import(WebConfig.class)
public class TestConfig {
@Autowired
private DataSource dataSource;
@Bean
public SpringLiquibase getLiquibase() {
final SpringLiquibase liquibase = new SpringLiquibase();
liquibase.setDataSource(dataSource);
liquibase.setChangeLog("classpath:setup-db.xml");
return liquibase;
}
}
4. Write integration test
In setUp method, we're populating a context object with in-memory db parameters.
@RunWith(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@ContextConfiguration(classes = {TestConfig.class})
public class MapAnomalyReportEndpointIntTest {
@Autowired
private WebApplicationContext context;
@BeforeClass
public static void setup() throws IllegalStateException, NamingException {
final SimpleNamingContextBuilder context = SimpleNamingContextBuilder.emptyActivatedContextBuilder();
context.bind("java:comp/env/report/db/driverClass", "org.hsqldb.jdbc.JDBCDriver");
context.bind("java:comp/env/report/db/url", "jdbc:hsqldb:mem:reportdb;shutdown=false");
context.bind("java:comp/env/report/db/user", "sa");
context.bind("java:comp/env/report/db/password", "");
context.bind("java:comp/env/report/db/schema", "report");
context.activate();
}
@Test
public void testGetReports() throws Exception {
MockMvcBuilders.webAppContextSetup(context).build() //
.perform(get("/reports")) //
.andDo(print()) //
.andExpect(status().isOk()) //
.andExpect(content().contentType("application/json;charset=UTF-8")) //
.andExpect(jsonPath("$[0].id").value(1)); // TODO assert other values
}
}
5. Run the tests, this wont require you to configure jetty, deploy the ws and run test against them!
You can clone the whole project from here.
PS: The given project is built using Gradle as I want to learn it.
Comments