spring testing
DESCRIPTION
Speaker: Mattias Severson Is it possible to decrease the turn-around time of your test suite? How can you make sure that your tests execute independently? Is it possible to automatically verify that the database schema is kept in sync with the source code? What are the trade-offs? In this presentation, you will learn how to apply features such as the Spring MVC Test Framework, Spring profiles, and embedded databases, to automate and improve your test suite, thus improving the overall quality of your project. A simplistic Spring web app will be used to show some practical code examples. Topics include: Basic Spring Testing Embedded Database Transactions Profiles Controller Tests Server Integration TestsTRANSCRIPT
© 2013 SpringOne 2GX. All rights reserved. Do not distribute without permission.
Spring TestingMattias Severson
Agenda
• Basic Spring Testing
• Embedded Database
• Transactions
• Profiles
• Controller Tests
• Server Integration Tests
2
3
Mattias
Bank App
4
AccountService
BankController
ImmutableAccount
AccountEntityAccountRepository
5
Architecture
Basics
6
jUnit Test
public class AccountServiceTest {
AccountService aService;
@Before public void setUp() { aService = new AccountServiceImpl(); }
@Test public void testDoSomething() { aService.doSomething(); // verify ... }}
7
public class AccountServiceTest {
@Autowired AccountService aService;
@Test public void testDoSomething() { aService.doSomething(); // verify ... }}
@Autowired
8
@ContextConfiguration("/application-context.xml")public class AccountServiceTest {
@Autowired AccountService aService;
@Test public void testDoSomething() { aService.doSomething(); // verify ... }}
public class AccountServiceTest {
@Autowired AccountService aService;
@Test public void testDoSomething() { aService.doSomething(); // verify ... }}
9
@ContextConfiguration
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("/application-context.xml")public class AccountServiceTest {
@Autowired AccountService aService;
@Test public void testDoSomething() { aService.doSomething(); // verify ... }}
@ContextConfiguration("/application-context.xml")public class AccountServiceTest {
@Autowired AccountService aService;
@Test public void testDoSomething() { aService.doSomething(); // verify ... }}
10
SpringJUnit4ClassRunner
• Caches ApplicationContext –static memory–unique context configuration–within the same test suite
• All tests execute in the same JVM
11
@ContextConfiguration
• @Before / @After–Mockito.reset(mockObject)–EasyMock.reset(mockObject)
• @DirtiesContext
12
Mocked Beans
Embedded DB
13
AccountRepository AccountEntity
XML Config
<jdbc:embedded-database id="dataSource" type="HSQL"> <jdbc:script location="classpath:db-schema.sql"/> <jdbc:script location="classpath:db-test-data.sql"/></jdbc:embedded-database>
14
Java Config
@Configurationpublic class EmbeddedDbConfig {
@Bean public DataSource dataSource() { return new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.HSQL) .addScript(“classpath:db-schema.sql”) .addScript(“classpath:db-test-data.sql”) .build(); }}
15
Demo
16
Transactions
17
Tx Test
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("/application-context.xml")public class AccountServiceTest {
@Test public void testDoSomething() { // call DB }
}
@Transactional
@Test public void testDoSomething() { // call DB }
18
Tx Annotations
• @TransactionConfiguration
• @BeforeTransaction
• @AfterTransaction
• @Rollback
19
Avoid False Positives
• Always flush() before validation!
–JPA • entityManager.flush();
–Hibernate• sessionFactory.getCurrentSession().flush();
20
Demo
21
No Transactions?
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("...")public class AccountRepositoryTest {
@Autowired AccountRepository accountRepo;
@Before public void setUp() { accountRepo.deleteAll(); accountRepo.save(testData); }}
22
Spring Profiles
23
XML Profiles
<beans ...>
<bean id="dataSource"> <!-- Test data source --> </bean>
<bean id="dataSource"> <!-- Production data source --> </bean>
</beans>
<beans profile="testProfile">
</beans>
<beans profile="prodProfile">
</beans>
24
Java Config Profile
@Configurationpublic class EmbeddedDbConfig {
@Bean public DataSource dataSource() { return new EmbeddedDatabaseBuilder(). // ... }}
@Profile(“testProfile”)
25
Component Profile
@Componentpublic class SomeClass implements SomeInterface {
}
@Profile(“testProfile”)
26
Tests and Profiles
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(“/application-context.xml”)public class SomeTest {
@Autowired SomeClass someClass;
@Test public void testSomething() { ... }}
@ActiveProfiles("testProfile")
27
Demo
28
AccountRepository AccountEntity
AccountService ImmutableAccount
web.xml
<web-app ...>
<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
</web-app>
<context-param> <param-name>spring.profiles.active</param-name> <param-value>someProfile</param-value> </context-param>
29
ApplicationContext
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();ctx.getEnvironment().setActiveProfiles("someProfile");ctx.register(SomeConfig.class);ctx.scan("com.jayway.demo");ctx.refresh();
30
Env Property
System.getProperty(“spring.profiles.active”);
mvn -Dspring.profiles.active=testProfile
31
Default Profiles
ctx.getEnvironment().setDefaultProfiles("...");
System.getProperty("spring.profiles.default");
32
<context-param> <param-name>spring.profiles.default</param-name> <param-value>defaultProfile</param-value></context-param>
<beans profile="default"> <!-- default beans --></beans>
@Profile("default")
Profile Alternatives
33
• .properties
• Maven Profile
Test Controller AccountRepository
AccountService
AccountEntity
ImmutableAccount
BankController
34
Spring MVC Test Framework
• Call Controllers through DispatcherServlet
• MockHttpServletRequest• MockHttpServletResponse
35
MockMvc
MockMvc mockMvc = MockMvcBuilders .standaloneSetup(new BankController()) .build();
36
MockMvc mockMvc = MockMvcBuilders .standaloneSetup(new BankController()) .setMessageConverters(...) .setValidator(...) .setConversionService(...) .addInterceptors(...) .setViewResolvers(...) .setLocaleResolver(...) .addFilter(...) .build();
Assertions
mockMvc.perform(get("/url") .accept(MediaType.APPLICATION_XML)) .andExpect(response().status().isOk()) .andExpect(content().contentType(“MediaType.APPLICATION_XML”)) .andExpect(xpath(“key”).string(“value”)) .andExpect(redirectedUrl(“url”)) .andExpect(model().attribute(“name”, value));
37
@WebAppConfiguration
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("/application-context.xml")@WebAppConfigurationpublic class WebApplicationTest {
@Autowired WebApplicationContext wac;
MockMvc mockMvc;
@Before public void setup() { mockMvc = MockMvcBuilders .webAppContextSetup(wac) .build(); }
38
Demo
39
Testing Views
• Supported templates–JSON–XML–Velocity–Thymeleaf
• Except JSP
40
Server Integration Tests
41
appCtx
Spring Integration Test
42
Embedded DB
txMngr
test
dataSrc
App Server
appCtx
Server Integration Test
43
Embedded DB
txMngr
test
dataSrc
HTTP
App Server
App Server
44
appCtx
DB
txMngrdataSrc
testAppCtx
dataSrc
testHTTP
jetty-maven-plugin<executions> <execution> <id>start-jetty</id> <phase>pre-integration-test</phase> <goals> <goal>run</goal> </goals> </execution> <execution> <id>stop-jetty</id> <phase>post-integration-test</phase> <goals> <goal>stop</goal> </goals> </execution></executions>
45
maven-failsafe-plugin
**/IT*.java**/*IT.java**/*ITCase.java
46
Test RESTful API
47
• RestTemplate• Selenium• HttpClient• ...
REST Assured
@Test public void shouldGetSingleAccount() { expect(). statusCode(HttpStatus.SC_OK). contentType(ContentType.JSON). body("accountNumber", is(1)). body("balance", is(100)). when(). get("/account/1"); }
48
Demo
49
Questions?
50
Learn More. Stay Connected.
Talk to us on Twitter: @springcentralFind session replays on YouTube: spring.io/video
@mattiasseverson
http://blog.jayway.com/author/mattiasseverson/