0
Spring 3.1 and MVC        Testing Support                     Sam Brannen                         Swiftmind               ...
Sam BrannenSenior Software Consultant @ SwiftmindJava developer with 13+ years experienceSpring Framework Core DeveloperLe...
Rossen StoyanchevStaff Engineer SpringSource, VMwareSpring MVC, Spring Web Flow committerTeach and consult, Spring Project...
Goals of the      PresentationGain an overview of testing featuresin Spring 3.1Learn about the new Spring MVCTest Support ...
AgendaSpring TestContext FrameworkTesting with @Configuration ClassesTesting with Environment ProfilesSpring MVC Test Supp...
Show of Hands...JUnit / TestNGSpring 2.5 / 3.0 / 3.1Integration testing with SpringSpring TestContext FrameworkSpring MVCS...
Spring TestContext    Framework
Introduced in Spring 2.5
Revised in Spring 3.1
Unit and integration testing
Annotation-driven
Convention over Configuration
JUnit & TestNG
Spring & Unit TestingPOJO-based programming modelProgram to interfacesIoC / Dependency InjectionOut-of-container testabili...
Spring & Integration Testing ApplicationContext   management & caching Dependency injection of test instances Transactiona...
Spring Test AnnotationsApplication Contexts   @ContextConfiguration, @DirtiesContext@TestExecutionListenersDependency Inje...
Spring JUnit Annotations  Testing Profiles    groups, not bean definition    profiles    @IfProfileValue,    @ProfileValue...
Using the TestContext     FrameworkUse the SpringJUnit4ClassRunner forJUnit 4.5+Instrument test class withTestContextManag...
Example: @POJO Test Classpublic class OrderServiceTests {    @Test    public void testOrderService() { … }}
Example: @POJO Test Class@RunWith(SpringJUnit4ClassRunner.class)public class OrderServiceTests {    @Test    public void t...
Example: @POJO Test Class@RunWith(SpringJUnit4ClassRunner.class)@ContextConfigurationpublic class OrderServiceTests {    @...
Example: @POJO Test Class@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration // defaults to// OrderServiceTests-c...
Example: @POJO Test Class@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration // defaults to// OrderServiceTests-c...
Example: @POJO Test Class@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration // defaults to// OrderServiceTests-c...
Example: @POJO Test Class@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration // defaults to// OrderServiceTests-c...
Example: @POJO Test Class@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration // defaults to// OrderServiceTests-c...
Core Components
TestContextTracks context for current testDelegates to a ContextLoaderCaches ApplicationContext
TestContextManagerManages the TestContextSignals events to listeners:  before: before-class methods  after: test instantia...
TestExecutionListener             SPIReacts to test execution events  Receives reference to current TestContextOut of the ...
TestExecutionListener
TEL: Prepare Instance
TEL: Befores and Afters
ContextLoader          SPIStrategy for loading application contexts   from resource locationsOut of the box:  GenericXmlCo...
ContextLoader   2.5
Putting it all together
New in Spring 3.1
Support for ...
testing with @Configuration classes
and
testing with environment profiles
made possible by ...
SmartContextLoader
AnnotationConfigContextLoader
DelegatingSmartContextLoader
updated context cache key generation
SmartContextLoader           SPISupersedes ContextLoaderStrategy for loading applicationcontextsFrom @Configuration classe...
ImplementationsGenericXmlContextLoaderGenericPropertiesContextLoaderAnnotationConfigContextLoaderDelegatingSmartContextLoa...
ContextLoader   2.5
ContextLoader   3.1
Testing with@Configuration Classes
@ContextConfiguration   accepts a new classes attribute...
@ContextConfiguration(    classes={DataAccessConfig.class,             ServiceConfig.class})
First, a review with XML config for           comparison...
OrderServiceTest-context.xml<?xml version="1.0" encoding="UTF-8"?><beans ...>  <!-- will be injected into OrderServiceTest...
OrderServiceTest.javapackage com.example;@RunWith(SpringJUnit4ClassRunner.class)@ContextConfigurationpublic class OrderSer...
Lets rework that example to use a @Configuration class and the new  AnnotationConfigContextLoader...
OrderServiceTest.java@RunWith(SpringJUnit4ClassRunner.class)public class OrderServiceTest {    @Autowired    private Order...
OrderServiceTest.java@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(    loader=AnnotationConfigContextLoader...
OrderServiceTest.java@RunWith(SpringJUnit4ClassRunner.class)@ContextConfigurationpublic class OrderServiceTest {    @Autow...
OrderServiceTest.java@RunWith(SpringJUnit4ClassRunner.class)@ContextConfigurationpublic class OrderServiceTest {    @Confi...
OrderServiceTest.java@RunWith(SpringJUnit4ClassRunner.class)@ContextConfigurationpublic class OrderServiceTest {    @Confi...
Whats changed?No XMLBean definitions are converted toJava  using @Configuration and @BeanOtherwise, the test remainsunchan...
But what if we dont want a static    inner @Configuration class?
Just externalize the config...
OrderServiceConfig.java@Configurationpublic class OrderServiceConfig {    @Bean // will be injected into OrderServiceTest ...
And reference the config classes in      @ContextConfiguration...
OrderServiceConfig.java@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes=OrderServiceConfig.class)publi...
@Configuration + XML Q: How can we combine @Configuration classes with XML config? A: Choose one as the entry point. Thats...
Importing Configuration In XML:   include @Configuration classes via   component scanning   or define them as normal Sprin...
Testing withEnvironment Profiles
@ActiveProfiles  To activate bean definition profiles in tests...Annotate a test class with@ActiveProfilesSupply a list of...
Lets look at an example with XML              config...
app-config.xml           (1/2)<beans ... >   <bean id="transferService"       class="com.example.DefaultTransferService"> ...
app-config.xml           (2/2)<beans ... >   <!-- transferService, accountRepository, feePolicy --></beans>
app-config.xml           (2/2)<beans ... >   <!-- transferService, accountRepository, feePolicy -->   <beans profile="prod...
app-config.xml           (2/2)<beans ... >   <!-- transferService, accountRepository, feePolicy -->   <beans profile="prod...
TransferServiceTest.java@RunWith(SpringJUnit4ClassRunner.class)public class TransferServiceTest {    @Autowired    private...
TransferServiceTest.java@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("/app-config.xml")public class Transf...
TransferServiceTest.java@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("/app-config.xml")@ActiveProfiles("de...
And now an example with  @Configuration classes
TransferServiceConfig.java@Configurationpublic class TransferServiceConfig {    @Autowired DataSource dataSource;    @Bean...
}              JndiDataConfig.java@Configuration@Profile("production")public class JndiDataConfig {    @Bean    public Dat...
StandaloneDataConfig.java@Configuration@Profile("dev")public class StandaloneDataConfig {    @Bean    public DataSource da...
And finally the test class...
TransferServiceTest.javapackage com.bank.service;@RunWith(SpringJUnit4ClassRunner.class)public class TransferServiceTest {...
TransferServiceTest.javapackage com.bank.service;@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(    classes=...
TransferServiceTest.javapackage com.bank.service;@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(    classes=...
Active Profile Inheritance@ActiveProfiles   supports inheritance as wellVia the inheritProfiles attributeSee Javadoc for a...
ApplicationContext      Caching
Until Spring 3.1
application contexts were cached
but using only resource locations for              the key.
Now there are different   requirements...
New Key Generation AlgorithmThe context cache key generation algorithm has been updated to include...     locations (from ...
SummaryThe Spring TestContext Framework simplifiesintegration testing of Spring-basedapplicationsSpring 3.1 provides first...
Spring MVC Test    Support
How Do You Test an   @Controller?
@Controller@RequestMapping("/accounts")public class AccountController {// ...    @ModelAttribute    public Account getAcco...
Unit Test?     Create controller instanceMock or stub services & repositories
Example@Testpublic void testSave() {    Account account = new Account();    BindingResult result =        new BeanProperty...
Example@Testpublic void testSave() {    Account account = new Account();    BindingResult result =        new BeanProperty...
Example@Testpublic void testSave() {    Account account = new Account();    BindingResult result =        new BeanProperty...
Example@Testpublic void testSave() {    Account account = new Account();    BindingResult result =        new BeanProperty...
Example With Failure@Testpublic void testSave() {    Account account = new Account();    BindingResult result =        new...
Example With Failure@Testpublic void testSave() {    Account account = new Account();    BindingResult result =        new...
Example With Failure@Testpublic void testSave() {    Account account = new Account();    BindingResult result =        new...
Not Fully Tested  Request mappings    Binding errors   Type conversion         Etc.
Integration Test?      Selenium      JWebUnit        etc.
It Requires...A running servlet container  More time to execute More effort to maintain   Server is a black box
Actually...
its an end-to-end test
the only way to verify...         Client-side behaviorInteraction with other server instances          Redis, Rabbit, etc.
Wed also like to...   Test controllers once!      Fully & quickly    Execute tests often
In summary...We cant replace the need for end-to-              end tests     But we can minimize errors   Have confidence ...
Spring MVC Test         Built on spring-test         No Servlet container  Drives Spring MVC infrastructureBoth server & c...
The Approach  Re-use controller test fixturesI.e. mocked services & repositoriesInvoke @Controller classes through      @M...
ExampleString contextLoc = "classpath:appContext.xml";String warDir = "src/main/webapp";MockMvc mockMvc =  xmlConfigSetup(...
Under the CoversMock request/response from spring-test    DispatcherServlet   replacement   Multiple ways to initialize MV...
Ways To Initialize MVC   Infrastructure
From Existing XML Config// XML configMockMvc mockMvc =    xmlConfigSetup("classpath:appContext.xml")      .activateProfile...
From Existing Java Config// Java configMockMvc mockMvc =    annotationConfigSetup(WebConfig.class)      .activateProfiles(...
ManuallyMockMvc mockMvc =    standaloneSetup(new PersonController())      .setMessageConverters(..)      .setValidator(..)...
About Manual SetupMVC components instantiated directly   Not looked up in Spring context       Focused, readable testsBut ...
TestContext            Framework Example@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(        locations={"/...
TestContext       Framework Caches loaded Spring configuration     Potentially across all tests!
However...WebApplicationContext   not supported yet    To be supported in Spring 3.2
In the mean time...You can use a custom ContextLoader Example exists in spring-test-mvc
Step 1  Add static imports   MockMvcBuilders.*MockMvcRequestBuilders.*MockMvcResultActions.*
Easy to remember...       MockMvc*
Also in Eclipse...Add MockMvc* classes in Preferences   Java -> Editor -> Favorites       Helps content assist
Step 2              Initialize MVC infrastructureString contextLoc = "classpath:appContext.xml";String warDir = "src/main/...
Step 3                     Build RequestString contextLoc = "classpath:appContext.xml";String warDir = "src/main/webapp";M...
Step 4                   Add ExpectationsString contextLoc = "classpath:appContext.xml";String warDir = "src/main/webapp";...
Step 5                         DebugString contextLoc = "classpath:appContext.xml";String warDir = "src/main/webapp";MockM...
Demohttps://github.com/SpringSource/spring-test-mvc                Sample Tests:  org.springframework.test.web.server.samp...
Client-Side ExampleRestTemplate restTemplate = ... ;MockRestServiceServer.createServer(restTemplate)    .expect(requestTo(...
Project Availabilitygithub.com/SpringSource/spring-test-mvc        Request for feedback!           Send comments          ...
Nightly Snapshot Available<repository>    <id>org.springframework.maven.snapshot</id>    <name>Spring Maven Snapshot Repos...
In Closing ...
This PresentationSource:https://github.com/rstoyanchev/spring-31-and-mvc-testing-supportSlides:http://rstoyanchev.github.c...
Resources for Spring MVC TestProject Home:https://github.com/SpringSource/spring-test-mvcSample Tests:org.springframework....
Resources for Core SpringSpring Framework:http://www.springsource.org/spring-coreReference Manual: Spring 3.1 RC1Forums: h...
Q&A  Sam Brannen  Web: Swiftmind.com Twitter: @sam_brannenRossen Stoyanchev Web: SpringSource.com   Twitter: @rstoya05
Prochain SlideShare
Chargement dans... 5
×

Spring 3.1 and MVC Testing Support

11,228

Published on

This session will give attendees an overview of the new testing features in Spring 3.1 as well the new Spring MVC test support. Sam Brannen will demonstrate how to use the Spring TestContext Framework to write integration tests for Java-based Spring configuration using @Configuration classes. He'll then compare and contrast this approach with XML-based configuration and follow up with a discussion of the new testing support for bean definition profiles. Next, Rossen Stoyanchev will show attendees how testing server-side code with annotated controllers and client-side code with the RestTemplate just got a whole lot easier with the new Spring MVC test support. Come to this session to see these new Spring testing features in action and learn how you can get involved in the Spring MVC Test Support project.

Published in: Technologies
0 commentaires
8 mentions J'aime
Statistiques
Remarques
  • Soyez le premier à commenter

Aucun téléchargement
Vues
Total des vues
11,228
Sur Slideshare
0
À partir des ajouts
0
Nombre d'ajouts
8
Actions
Partages
0
Téléchargements
242
Commentaires
0
J'aime
8
Ajouts 0
No embeds

No notes for slide

Transcript of "Spring 3.1 and MVC Testing Support"

  1. 1. Spring 3.1 and MVC Testing Support Sam Brannen Swiftmind Rossen Stoyanchev SpringSource, VMwareSpringOne 2GXOctober 28, 2011
  2. 2. Sam BrannenSenior Software Consultant @ SwiftmindJava developer with 13+ years experienceSpring Framework Core DeveloperLead author of Spring in a NutshellPrevious SpringSource dm Server™ developerPresenter on Spring, Java, OSGi, and testing
  3. 3. Rossen StoyanchevStaff Engineer SpringSource, VMwareSpring MVC, Spring Web Flow committerTeach and consult, Spring ProjectsSpring Web course authorNYC area
  4. 4. Goals of the PresentationGain an overview of testing featuresin Spring 3.1Learn about the new Spring MVCTest Support project
  5. 5. AgendaSpring TestContext FrameworkTesting with @Configuration ClassesTesting with Environment ProfilesSpring MVC Test SupportQ&A
  6. 6. Show of Hands...JUnit / TestNGSpring 2.5 / 3.0 / 3.1Integration testing with SpringSpring TestContext FrameworkSpring MVCSpring MVC Test Support
  7. 7. Spring TestContext Framework
  8. 8. Introduced in Spring 2.5
  9. 9. Revised in Spring 3.1
  10. 10. Unit and integration testing
  11. 11. Annotation-driven
  12. 12. Convention over Configuration
  13. 13. JUnit & TestNG
  14. 14. Spring & Unit TestingPOJO-based programming modelProgram to interfacesIoC / Dependency InjectionOut-of-container testabilityTesting mocks/stubs for various APIs: Servlet,Portlet, JNDIGeneral purpose testing utilities ReflectionTestUtils ModelAndViewAssert
  15. 15. Spring & Integration Testing ApplicationContext management & caching Dependency injection of test instances Transactional test management with default rollback semantics SimpleJdbcTestUtils JUnit 3.8 support classes are deprecated as of Spring 3.0/3.1
  16. 16. Spring Test AnnotationsApplication Contexts @ContextConfiguration, @DirtiesContext@TestExecutionListenersDependency Injection @Autowired, @Qualifier, @Inject, …Transactions @Transactional, @TransactionConfiguration, @Rollback, @BeforeTransaction, @AfterTransaction
  17. 17. Spring JUnit Annotations Testing Profiles groups, not bean definition profiles @IfProfileValue, @ProfileValueSourceConfiguration JUnit extensions @Timed, @Repeat
  18. 18. Using the TestContext FrameworkUse the SpringJUnit4ClassRunner forJUnit 4.5+Instrument test class withTestContextManager for TestNGExtend one of the base classes Abstract(Transactional)[JUnit4|TestNG]Spri
  19. 19. Example: @POJO Test Classpublic class OrderServiceTests { @Test public void testOrderService() { … }}
  20. 20. Example: @POJO Test Class@RunWith(SpringJUnit4ClassRunner.class)public class OrderServiceTests { @Test public void testOrderService() { … }}
  21. 21. Example: @POJO Test Class@RunWith(SpringJUnit4ClassRunner.class)@ContextConfigurationpublic class OrderServiceTests { @Test public void testOrderService() { … }}
  22. 22. Example: @POJO Test Class@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration // defaults to// OrderServiceTests-context.xml in same packagepublic class OrderServiceTests { @Test public void testOrderService() { … }}
  23. 23. Example: @POJO Test Class@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration // defaults to// OrderServiceTests-context.xml in same packagepublic class OrderServiceTests { @Autowired private OrderService orderService; @Test public void testOrderService() { … }}
  24. 24. Example: @POJO Test Class@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration // defaults to// OrderServiceTests-context.xml in same package@Transactionalpublic class OrderServiceTests { @Autowired private OrderService orderService; @Test public void testOrderService() { … }}
  25. 25. Example: @POJO Test Class@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration // defaults to// OrderServiceTests-context.xml in same package@Transactionalpublic class OrderServiceTests { @Autowired private OrderService orderService; @BeforeTransaction public void verifyInitialDatabaseState() { … } @Test public void testOrderService() { … }}
  26. 26. Example: @POJO Test Class@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration // defaults to// OrderServiceTests-context.xml in same package@Transactionalpublic class OrderServiceTests { @Autowired private OrderService orderService; @BeforeTransaction public void verifyInitialDatabaseState() { … } @Before public void setUpTestDataWithinTransaction() { … } @Test public void testOrderService() { … }}
  27. 27. Core Components
  28. 28. TestContextTracks context for current testDelegates to a ContextLoaderCaches ApplicationContext
  29. 29. TestContextManagerManages the TestContextSignals events to listeners: before: before-class methods after: test instantiation before: before methods after: after methods after: after-class methods
  30. 30. TestExecutionListener SPIReacts to test execution events Receives reference to current TestContextOut of the box: DependencyInjectionTestExecutionListener DirtiesContextTestExecutionListener TransactionalTestExecutionListener
  31. 31. TestExecutionListener
  32. 32. TEL: Prepare Instance
  33. 33. TEL: Befores and Afters
  34. 34. ContextLoader SPIStrategy for loading application contexts from resource locationsOut of the box: GenericXmlContextLoader GenericPropertiesContextLoader
  35. 35. ContextLoader 2.5
  36. 36. Putting it all together
  37. 37. New in Spring 3.1
  38. 38. Support for ...
  39. 39. testing with @Configuration classes
  40. 40. and
  41. 41. testing with environment profiles
  42. 42. made possible by ...
  43. 43. SmartContextLoader
  44. 44. AnnotationConfigContextLoader
  45. 45. DelegatingSmartContextLoader
  46. 46. updated context cache key generation
  47. 47. SmartContextLoader SPISupersedes ContextLoaderStrategy for loading applicationcontextsFrom @Configuration classes orresource locationsSupports environment profiles
  48. 48. ImplementationsGenericXmlContextLoaderGenericPropertiesContextLoaderAnnotationConfigContextLoaderDelegatingSmartContextLoader
  49. 49. ContextLoader 2.5
  50. 50. ContextLoader 3.1
  51. 51. Testing with@Configuration Classes
  52. 52. @ContextConfiguration accepts a new classes attribute...
  53. 53. @ContextConfiguration( classes={DataAccessConfig.class, ServiceConfig.class})
  54. 54. First, a review with XML config for comparison...
  55. 55. OrderServiceTest-context.xml<?xml version="1.0" encoding="UTF-8"?><beans ...> <!-- will be injected into OrderServiceTest --> <bean id="orderService" class="com.example.OrderServiceImpl"> <!-- set properties, etc. --> </bean> <!-- other beans --></beans>
  56. 56. OrderServiceTest.javapackage com.example;@RunWith(SpringJUnit4ClassRunner.class)@ContextConfigurationpublic class OrderServiceTest { @Autowired private OrderService orderService; @Test public void testOrderService() { // test the orderService }}
  57. 57. Lets rework that example to use a @Configuration class and the new AnnotationConfigContextLoader...
  58. 58. OrderServiceTest.java@RunWith(SpringJUnit4ClassRunner.class)public class OrderServiceTest { @Autowired private OrderService orderService; // @Test methods ...}
  59. 59. OrderServiceTest.java@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration( loader=AnnotationConfigContextLoader.class)public class OrderServiceTest { @Autowired private OrderService orderService; // @Test methods ...}
  60. 60. OrderServiceTest.java@RunWith(SpringJUnit4ClassRunner.class)@ContextConfigurationpublic class OrderServiceTest { @Autowired private OrderService orderService; // @Test methods ...}
  61. 61. OrderServiceTest.java@RunWith(SpringJUnit4ClassRunner.class)@ContextConfigurationpublic class OrderServiceTest { @Configuration static class Config { } @Autowired private OrderService orderService; // @Test methods ...}
  62. 62. OrderServiceTest.java@RunWith(SpringJUnit4ClassRunner.class)@ContextConfigurationpublic class OrderServiceTest { @Configuration static class Config { @Bean // will be injected into OrderServiceTest public OrderService orderService() { OrderService orderService = new OrderServiceImpl(); // set properties, etc. return orderService; } } @Autowired private OrderService orderService; // @Test methods ...}
  63. 63. Whats changed?No XMLBean definitions are converted toJava using @Configuration and @BeanOtherwise, the test remainsunchanged
  64. 64. But what if we dont want a static inner @Configuration class?
  65. 65. Just externalize the config...
  66. 66. OrderServiceConfig.java@Configurationpublic class OrderServiceConfig { @Bean // will be injected into OrderServiceTest public OrderService orderService() { OrderService orderService = new OrderServiceImpl(); // set properties, etc. return orderService; }}
  67. 67. And reference the config classes in @ContextConfiguration...
  68. 68. OrderServiceConfig.java@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes=OrderServiceConfig.class)public class OrderServiceTest { @Autowired private OrderService orderService; @Test public void testOrderService() { // test the orderService }}
  69. 69. @Configuration + XML Q: How can we combine @Configuration classes with XML config? A: Choose one as the entry point. Thats how it works in production anyway
  70. 70. Importing Configuration In XML: include @Configuration classes via component scanning or define them as normal Spring beans In an @Configuration class: use @ImportResource to import XML config files
  71. 71. Testing withEnvironment Profiles
  72. 72. @ActiveProfiles To activate bean definition profiles in tests...Annotate a test class with@ActiveProfilesSupply a list of profiles to beactivated for the testCan be used with @Configurationclasses and XML config
  73. 73. Lets look at an example with XML config...
  74. 74. app-config.xml (1/2)<beans ... > <bean id="transferService" class="com.example.DefaultTransferService"> <constructor-arg ref="accountRepository"/> <constructor-arg ref="feePolicy"/> </bean> <bean id="accountRepository" class="com.example.JdbcAccountRepository"> <constructor-arg ref="dataSource"/> </bean> <bean id="feePolicy" class="com.example.ZeroFeePolicy"/> <!-- dataSource --></beans>
  75. 75. app-config.xml (2/2)<beans ... > <!-- transferService, accountRepository, feePolicy --></beans>
  76. 76. app-config.xml (2/2)<beans ... > <!-- transferService, accountRepository, feePolicy --> <beans profile="production"> <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/datasource"/> </beans></beans>
  77. 77. app-config.xml (2/2)<beans ... > <!-- transferService, accountRepository, feePolicy --> <beans profile="production"> <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/datasource"/> </beans> <beans profile="dev"> <jdbc:embedded-database id="dataSource"> <jdbc:script location="classpath:schema.sql"/> <jdbc:script location="classpath:test-data.sql"/> </jdbc:embedded-database> </beans></beans>
  78. 78. TransferServiceTest.java@RunWith(SpringJUnit4ClassRunner.class)public class TransferServiceTest { @Autowired private TransferService transferService; @Test public void testTransferService() { // test the transferService }}
  79. 79. TransferServiceTest.java@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("/app-config.xml")public class TransferServiceTest { @Autowired private TransferService transferService; @Test public void testTransferService() { // test the transferService }}
  80. 80. TransferServiceTest.java@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("/app-config.xml")@ActiveProfiles("dev")public class TransferServiceTest { @Autowired private TransferService transferService; @Test public void testTransferService() { // test the transferService }}
  81. 81. And now an example with @Configuration classes
  82. 82. TransferServiceConfig.java@Configurationpublic class TransferServiceConfig { @Autowired DataSource dataSource; @Bean public TransferService transferService() { return new DefaultTransferService(accountRepository(), feePolicy()); } @Bean public AccountRepository accountRepository() { return new JdbcAccountRepository(dataSource); } @Bean public FeePolicy feePolicy() { return new ZeroFeePolicy(); }}
  83. 83. } JndiDataConfig.java@Configuration@Profile("production")public class JndiDataConfig { @Bean public DataSource dataSource() throws Exception { Context ctx = new InitialContext(); return (DataSource) ctx.lookup("java:comp/env/jdbc/datasource"); }}
  84. 84. StandaloneDataConfig.java@Configuration@Profile("dev")public class StandaloneDataConfig { @Bean public DataSource dataSource() { return new EmbeddedDatabaseBuilder() .setType(EmbeddedDatabaseType.HSQL) .addScript("classpath:schema.sql") .addScript("classpath:test-data.sql") .build(); }}
  85. 85. And finally the test class...
  86. 86. TransferServiceTest.javapackage com.bank.service;@RunWith(SpringJUnit4ClassRunner.class)public class TransferServiceTest { @Autowired private TransferService transferService; @Test public void testTransferService() { // test the transferService }}
  87. 87. TransferServiceTest.javapackage com.bank.service;@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration( classes={ TransferServiceConfig.class, StandaloneDataConfig.class, JndiDataConfig.class})public class TransferServiceTest { @Autowired private TransferService transferService; @Test public void testTransferService() { // test the transferService }}
  88. 88. TransferServiceTest.javapackage com.bank.service;@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration( classes={ TransferServiceConfig.class, StandaloneDataConfig.class, JndiDataConfig.class})@ActiveProfiles("dev")public class TransferServiceTest { @Autowired private TransferService transferService; @Test public void testTransferService() { // test the transferService }}
  89. 89. Active Profile Inheritance@ActiveProfiles supports inheritance as wellVia the inheritProfiles attributeSee Javadoc for an example
  90. 90. ApplicationContext Caching
  91. 91. Until Spring 3.1
  92. 92. application contexts were cached
  93. 93. but using only resource locations for the key.
  94. 94. Now there are different requirements...
  95. 95. New Key Generation AlgorithmThe context cache key generation algorithm has been updated to include... locations (from @ContextConfiguration) classes (from @ContextConfiguration) contextLoader (from @ContextConfiguration) activeProfiles (from @ActiveProfiles)
  96. 96. SummaryThe Spring TestContext Framework simplifiesintegration testing of Spring-basedapplicationsSpring 3.1 provides first-class testing supportfor: @Configuration classes Environment profilesSee the Testing with @Configuration Classesand Profiles blog for further insight
  97. 97. Spring MVC Test Support
  98. 98. How Do You Test an @Controller?
  99. 99. @Controller@RequestMapping("/accounts")public class AccountController {// ... @ModelAttribute public Account getAccount(String number) { return this.accountManager.getAccount(number); } @RequestMapping(method = RequestMethod.POST) public String save(@Valid Account account, BindingResult result) { if (result.hasErrors()) { return "accounts/edit"; } this.accountManager.saveOrUpdate(account); return "redirect:accounts"; }}
  100. 100. Unit Test? Create controller instanceMock or stub services & repositories
  101. 101. Example@Testpublic void testSave() { Account account = new Account(); BindingResult result = new BeanPropertyBindingResult(account, "account");}
  102. 102. Example@Testpublic void testSave() { Account account = new Account(); BindingResult result = new BeanPropertyBindingResult(account, "account"); AccountManager mgr = createMock(AccountManager.class); mgr.saveOrUpdate(account); replay(mgr);}
  103. 103. Example@Testpublic void testSave() { Account account = new Account(); BindingResult result = new BeanPropertyBindingResult(account, "account"); AccountManager mgr = createMock(AccountManager.class); mgr.saveOrUpdate(account); replay(mgr); AccountController contrlr = new AccountController(mgr); String view = contrlr.save(account, result);}
  104. 104. Example@Testpublic void testSave() { Account account = new Account(); BindingResult result = new BeanPropertyBindingResult(account, "account"); AccountManager mgr = createMock(AccountManager.class); mgr.saveOrUpdate(account); replay(mgr); AccountController contrlr = new AccountController(mgr); String view = contrlr.save(account, result); assertEquals("redirect:accounts", view); verify(mgr);}
  105. 105. Example With Failure@Testpublic void testSave() { Account account = new Account(); BindingResult result = new BeanPropertyBindingResult(account, "account"); result.reject("error.code", "default message")}
  106. 106. Example With Failure@Testpublic void testSave() { Account account = new Account(); BindingResult result = new BeanPropertyBindingResult(account, "account"); result.reject("error.code", "default message") AccountManager mgr = createMock(AccountManager.class); replay(mgr);}
  107. 107. Example With Failure@Testpublic void testSave() { Account account = new Account(); BindingResult result = new BeanPropertyBindingResult(account, "account"); result.reject("error.code", "default message") AccountManager mgr = createMock(AccountManager.class); replay(mgr); AccountController contrlr = new AccountController(mgr); String view = contrlr.save(account, result); assertEquals("accounts/edit", view); verify(mgr);}
  108. 108. Not Fully Tested Request mappings Binding errors Type conversion Etc.
  109. 109. Integration Test? Selenium JWebUnit etc.
  110. 110. It Requires...A running servlet container More time to execute More effort to maintain Server is a black box
  111. 111. Actually...
  112. 112. its an end-to-end test
  113. 113. the only way to verify... Client-side behaviorInteraction with other server instances Redis, Rabbit, etc.
  114. 114. Wed also like to... Test controllers once! Fully & quickly Execute tests often
  115. 115. In summary...We cant replace the need for end-to- end tests But we can minimize errors Have confidence in @MVC code During end-to-end tests
  116. 116. Spring MVC Test Built on spring-test No Servlet container Drives Spring MVC infrastructureBoth server & client-side test support (i.e. RestTemplate code) Inspired by spring-ws-test
  117. 117. The Approach Re-use controller test fixturesI.e. mocked services & repositoriesInvoke @Controller classes through @MVC infrastructure
  118. 118. ExampleString contextLoc = "classpath:appContext.xml";String warDir = "src/main/webapp";MockMvc mockMvc = xmlConfigSetup(contextLoc) .configureWebAppRootDir(warDir, false) .build();mockMvc.perform(post("/persons")) .andExpect(response().status().isOk()) .andExpect(response().forwardedUrl("/add.jsp")) .andExpect(model().size(1)) .andExpect(model().hasAttributes("person"));
  119. 119. Under the CoversMock request/response from spring-test DispatcherServlet replacement Multiple ways to initialize MVC infrastructure Save results for expectations
  120. 120. Ways To Initialize MVC Infrastructure
  121. 121. From Existing XML Config// XML configMockMvc mockMvc = xmlConfigSetup("classpath:appContext.xml") .activateProfiles(..) .configureWebAppRootDir(warDir, false) .build();
  122. 122. From Existing Java Config// Java configMockMvc mockMvc = annotationConfigSetup(WebConfig.class) .activateProfiles(..) .configureWebAppRootDir(warDir, false) .build();
  123. 123. ManuallyMockMvc mockMvc = standaloneSetup(new PersonController()) .setMessageConverters(..) .setValidator(..) .setConversionService(..) .addInterceptors(..) .setViewResolvers(..) .setLocaleResolver(..) .build();
  124. 124. About Manual SetupMVC components instantiated directly Not looked up in Spring context Focused, readable testsBut must verify MVC config separately
  125. 125. TestContext Framework Example@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration( locations={"/org/example/servlet-context.xml"})public class TestContextTests { @Autowired private WebApplicationContext wac; @Before public void setup() { MockMvc mockMvc = MockMvcBuilders.webApplicationContextSetup(this.wac) .build(); }}
  126. 126. TestContext Framework Caches loaded Spring configuration Potentially across all tests!
  127. 127. However...WebApplicationContext not supported yet To be supported in Spring 3.2
  128. 128. In the mean time...You can use a custom ContextLoader Example exists in spring-test-mvc
  129. 129. Step 1 Add static imports MockMvcBuilders.*MockMvcRequestBuilders.*MockMvcResultActions.*
  130. 130. Easy to remember... MockMvc*
  131. 131. Also in Eclipse...Add MockMvc* classes in Preferences Java -> Editor -> Favorites Helps content assist
  132. 132. Step 2 Initialize MVC infrastructureString contextLoc = "classpath:appContext.xml";String warDir = "src/main/webapp";MockMvc mockMvc = xmlConfigSetup("classpath:appContext.xml") .configureWebAppRootDir(warDir, false) .build()// ...
  133. 133. Step 3 Build RequestString contextLoc = "classpath:appContext.xml";String warDir = "src/main/webapp";MockMvc mockMvc = xmlConfigSetup("classpath:appContext.xml") .configureWebAppRootDir(warDir, false) .build()mockMvc.perform(get("/").accept(MediaType.APPLICATION_XML))// ...
  134. 134. Step 4 Add ExpectationsString contextLoc = "classpath:appContext.xml";String warDir = "src/main/webapp";MockMvc mockMvc = xmlConfigSetup("classpath:appContext.xml") .configureWebAppRootDir(warDir, false) .build()mockMvc.perform(get("/").accept(MediaType.APPLICATION_XML)) .andExpect(response().status().isOk()) .andExpect(response().contentType(MediaType)) .andExpect(response().content().xpath(String).exists()) .andExpect(response().redirectedUrl(String)) .andExpect(model().hasAttributes(String...));// ...
  135. 135. Step 5 DebugString contextLoc = "classpath:appContext.xml";String warDir = "src/main/webapp";MockMvc mockMvc = xmlConfigSetup("classpath:appContext.xml") .configureWebAppRootDir(warDir, false) .build()mockMvc.perform(get("/").accept(MediaType.APPLICATION_XML)) .andPrint(toConsole());// ...
  136. 136. Demohttps://github.com/SpringSource/spring-test-mvc Sample Tests: org.springframework.test.web.server.samples
  137. 137. Client-Side ExampleRestTemplate restTemplate = ... ;MockRestServiceServer.createServer(restTemplate) .expect(requestTo(String)) .andExpect(method(HttpMethod)) .andExpect(body(String)) .andExpect(headerContains(String, String)) .andRespond(withResponse(String, HttpHeaders));
  138. 138. Project Availabilitygithub.com/SpringSource/spring-test-mvc Request for feedback! Send comments Pull requests
  139. 139. Nightly Snapshot Available<repository> <id>org.springframework.maven.snapshot</id> <name>Spring Maven Snapshot Repository</name> <url>http://maven.springframework.org/snapshot</url> <releases> <enabled>false</enabled> </releases> <snapshots> <enabled>true</enabled> </snapshots></repository>
  140. 140. In Closing ...
  141. 141. This PresentationSource:https://github.com/rstoyanchev/spring-31-and-mvc-testing-supportSlides:http://rstoyanchev.github.com/spring-31-and-mvc-test
  142. 142. Resources for Spring MVC TestProject Home:https://github.com/SpringSource/spring-test-mvcSample Tests:org.springframework.test.web.server.samples
  143. 143. Resources for Core SpringSpring Framework:http://www.springsource.org/spring-coreReference Manual: Spring 3.1 RC1Forums: http://forum.springframework.orgJIRA: https://jira.springsource.orgSpring in a Nutshell … available in 2012
  144. 144. Q&A Sam Brannen Web: Swiftmind.com Twitter: @sam_brannenRossen Stoyanchev Web: SpringSource.com Twitter: @rstoya05
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×