Beginning Spring学习笔记——第7章 使用Spring进行测试驱动开发
来源:互联网 发布:网站编程常见单词 编辑:程序博客网 时间:2024/05/22 07:57
配置和缓存ApplicationContext
测试中使用基于XML和Java的上下文配置
首先创建maven项目,依赖配置如下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.lonelyquantum.springbeginning.wileybookch4</groupId> <artifactId>JDBCTest</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>JDBCTest</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <spring.version>4.3.10.RELEASE</spring.version> <junit.version>4.12</junit.version> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> </dependency> </dependencies></project>
在src/main/java下创建com.wiley.beginningspring.ch7包,创建第二章创建的一系列类和接口。
Account类:
public class Account { private long id; private String ownerName; private double balance; private Date accessTime; private boolean locked; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getOwnerName() { return ownerName; } public void setOwnerName(String ownerName) { this.ownerName = ownerName; } public double getBalance() { return balance; } public void setBalance(double balance) { this.balance = balance; } public Date getAccessTime() { return accessTime; } public void setAccessTime(Date accessTime) { this.accessTime = accessTime; } public boolean isLocked() { return locked; } public void setLocked(boolean locked) ` this.locked = locked; }}
AccountDao接口和其实现类AccountDaoInMemoryImpl:
public interface AccountDao { public void insert(Account account); public void update(Account account); public void update(List<Account> accounts); public void delete(long accountId); public Account find(long accountId); public List<Account> find(List<Long> accountIds); public List<Account> find(String ownerName); public List<Account> find(boolean locked);}public class AccountDaoInMemoryImpl implements AccountDao { private Map<Long,Account> accountsMap = new HashMap<>(); public void setAccountsMap(Map<Long, Account> accountsMap) { this.accountsMap = accountsMap; } { Account account1 = new Account(); account1.setId(1L); account1.setOwnerName("John"); account1.setBalance(10.0); Account account2 = new Account(); account2.setId(2L); account2.setOwnerName("Mary"); account2.setBalance(20.0); accountsMap.put(account1.getId(), account1); accountsMap.put(account2.getId(), account2); } @Override public void insert(Account account) { accountsMap.put(account.getId(), account); } @Override public void update(Account account) { accountsMap.put(account.getId(), account); } @Override public void update(List<Account> accounts) { for(Account account:accounts) { update(account); } } @Override public void delete(long accountId) { accountsMap.remove(accountId); } @Override public Account find(long accountId) { return accountsMap.get(accountId); } @Override public List<Account> find(List<Long> accountIds) { List<Account> accounts = new ArrayList<>(); for(Long id:accountIds) { accounts.add(accountsMap.get(id)); } return accounts; } @Override public List<Account> find(String ownerName) { List<Account> accounts = new ArrayList<>(); for(Account account:accountsMap.values()) { if(ownerName.equals(account.getOwnerName())) { accounts.add(account); } } return accounts; } @Override public List<Account> find(boolean locked) { List<Account> accounts = new ArrayList<>(); for(Account account:accountsMap.values()) { if(locked == account.isLocked()) { accounts.add(account); } } return accounts; }}
AccountService接口和其实现类AccountServiceImpl。
public interface AccountService { public void transferMoney(long sourceAccountId, long targetAccountId, double amount); public void depositMoney(long accountId, double amount) throws Exception; public Account getAccount(long accountId);}public class AccountServiceImpl implements AccountService { private AccountDao accountDao; public void setAccountDao(AccountDao accountDao) { this.accountDao = accountDao; } @Override public void transferMoney(long sourceAccountId, long targetAccountId, double amount) { Account sourceAccount = accountDao.find(sourceAccountId); Account targetAccount = accountDao.find(targetAccountId); sourceAccount.setBalance(sourceAccount.getBalance() - amount); targetAccount.setBalance(targetAccount.getBalance() + amount); accountDao.update(sourceAccount); accountDao.update(targetAccount); } @Override public void depositMoney(long accountId, double amount) throws Exception { Account account = accountDao.find(accountId); account.setBalance(account.getBalance() + amount); accountDao.update(account); } @Override public Account getAccount(long accountId) { return accountDao.find(accountId); } }
采用XML配置时,在src/main/resource下创建applicationContext.xml Bean配置文件。
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="accountService" class="com.wiley.beginningspring.ch7.AccountServiceImpl"> <property name="accountDao" ref="accountDao" /> </bean> <bean id="accountDao" class="com.wiley.beginningspring.ch7.AccountDaoInMemoryImpl"/></beans>
此时在src/test/java文件夹中创建com.wiley.beginningspring.ch7包并创建测试XML配置的测试类AccountIntegrationTests。
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("/applicationContext.xml")public class AccountIntegrationTests { @Autowired private AccountService accountService; @Test public void accountServiceShouldBeInjected() { Assert.assertNotNull(accountService); }}
作为JUnit测试运行通过,说明配置成功。
此外,还可以使用Java文件配置,此时不需要创建以上XML文件,而是在类包内创建配置类Ch7Configuration。
@Configurationpublic class Ch7Configuration { @Bean public AccountService accountService() { AccountServiceImpl bean = new AccountServiceImpl(); bean.setAccountDao(accountDao()); return bean; } @Bean public AccountDao accountDao() { AccountDaoInMemoryImpl bean = new AccountDaoInMemoryImpl(); //depedencies of accountDao bean will be injected here... return bean; }}
此时在测试包中创建的文件变为:
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes={Ch7Configuration.class})public class AccountIntegrationTestsWithJavaConfig { @Autowired private AccountService accountService; @Test public void accountServiceShouldBeInjected() { Assert.assertNotNull(accountService); }}
当然,也可以两种配置一起使用,此时测试类变为:
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes={Ch7Configuration.class,Config.class})public class AccountIntegrationTestsWithMixedConfig { @Configuration @ImportResource("classpath:/applicationContext.xml") static class Config { } @Autowired private AccountService accountService; @Test public void accountServiceShouldBeInjected() { Assert.assertNotNull(accountService); }}
此外还可以使用ApplicationContextInitializer来配置上下文,这时,先在一个TestInitializer类中完成配置文件的导入和上下文的预初始化:
public class TestInitializer implements ApplicationContextInitializer<GenericApplicationContext> { @Override public void initialize(GenericApplicationContext applicationContext) { XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(applicationContext); reader.loadBeanDefinitions("classpath:/applicationContext.xml"); }}
然后再利用该上下文进行测试:
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(initializers={TestInitializer.class})public class AccountIntegrationTestsWithInitializer { @Autowired private AccountService accountService; @Test public void accountServiceShouldBeInjected() { Assert.assertNotNull(accountService); }}
以上测试目录结构为:
继承上下文配置
继承于中间类或者基础类的类可以继承测试相关配置。
先展示目录结构:
首先创建如下两个类:
public class Bar {}public class Foo {}
然后创建基础类的配置文件baseContext.xml。
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="foo" class="com.wiley.beginningspring.ch7.Foo"/></beans>
接着创建子配置文件。
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="bar" class="com.wiley.beginningspring.ch7.Bar"/></beans>
然后创建基础测试类和孩子测试类:
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("classpath:/baseContext.xml")public class BaseTest { @Autowired protected Foo foo;}@ContextConfiguration("classpath:/subContext.xml")public class ChildTest extends BaseTest { @Autowired private Bar bar; @Test public void dependenciesShouldBeAvailable() { Assert.assertNotNull(foo); Assert.assertNotNull(bar); }}
运行孩子测试类通过,说明孩子测试类继承了基础测试类的配置文件。
ApplicationContext缓存
如果多个测试类指定了完全相同的XML位置和配置类,那么Spring TestContext Framework将只创建一次ApplicatoinContext实例,并在运行这些测试类之间共享该实例。
缓存被保存再一个静态变量中。
注入测试夹具的依赖项
项目目录结构如下:
首先创建如下两个类:
public class Bar {}public class Foo {}
然后创建测试类:
@Configurationpublic class Ch7ConfigurationForDependencyInjection { @Bean public Foo foo1() { return new Foo(); } @Bean public Foo foo2() { return new Foo(); } @Bean public Bar bar1() { return new Bar(); }}
最后创建测试类:
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration(classes=Ch7ConfigurationForDependencyInjection.class)public class DependencyInjectionTests { @Autowired @Qualifier("foo1") private Foo foo1; @Resource private Foo foo2; @Resource private Bar bar; @Test public void testInjections() { Assert.assertNotNull(foo1); Assert.assertNotNull(foo2); Assert.assertNotNull(bar); }}
运行通过测试,可见配置类中的依赖被成功注入到测试类中。
在测试中使用事务管理
在测试方法或者测试类级别使用@Transactional注解即可作为事务测试,通常测试后会进行回滚操作,如果不想回滚而是想提交事务,则需要另外设置不回滚。
@Test@Transactional@Rollback(false)public void transactionalTestMethod(){}
此外,使用ORM框架,如Hibernate或JPA时,要在测试方法结束时刷新当前Hibernate Session或者JPA EntityManager,否则由于测试结束后进行回滚,其上累积的持久化操作不会提交,SQL操作不会执行,导致无法检查由数据库交互失败的错误。
测试Web应用程序
此时需要支持web的依赖文件:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.lonelyquantum.springbeginning.wileybookch4</groupId> <artifactId>JDBCTest</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>JDBCTest</name> <url>http://maven.apache.org</url> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <spring.version>4.3.10.RELEASE</spring.version> <junit.version>4.12</junit.version> <javax.servlet.version>3.1.0</javax.servlet.version> </properties> <dependencies> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>${javax.servlet.version}</version> </dependency> </dependencies></project>
测试的目录结构为:
首先创建空的XML配置文件applicationContext.xml:
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"></beans>
然后创建如下测类:
@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("/applicationContext.xml")@WebAppConfigurationpublic class WebApplicationTests { @Autowired private WebApplicationContext applicationContext; @Autowired private MockServletContext servletContext; @Autowired private MockHttpServletRequest httpServletRequest; @Autowired private MockHttpServletResponse httpServletResponse; @Test public void testWebApp() { Assert.assertNotNull(applicationContext); Assert.assertNotNull(servletContext); Assert.assertNotNull(httpServletRequest); Assert.assertNotNull(httpServletResponse); }}
注意到类上使用了@WebAppConfiguration表示为Web项目。运行测试成功通过。
测试Request和Session作用域的Bean
依赖文件不变,目录结构如下:
首先创建如下三个类:
public class LoginAction { private String username; private String password; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; }}public class UserPreferences { private String theme; public String getTheme() { return theme; } public void setTheme(String theme) { this.theme = theme; }}public class UserService { private LoginAction loginAction; private UserPreferences userPreferences; public LoginAction getLoginAction() { return loginAction; } public void setLoginAction(LoginAction loginAction) { this.loginAction = loginAction; } public UserPreferences getUserPreferences() { return userPreferences; } public void setUserPreferences(UserPreferences userPreferences) { this.userPreferences = userPreferences; }}
用户操作和用户偏好为两个域类,而用户服务类中设置这两个域类实例。
在配置文件applicationContext.xml中用SpEL定义了他们的Bean并注入了依赖:
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.0.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="loginAction" class="com.wiley.beginningspring.ch7.LoginAction" scope="request"> <property name="username" value="#{request.getParameter('username')}"/> <property name="password" value="#{request.getParameter('password')}"/> <aop:scoped-proxy/> </bean> <bean id="userPreferences" class="com.wiley.beginningspring.ch7.UserPreferences" scope="session"> <property name="theme" value="#{session.getAttribute('theme')}"/> <aop:scoped-proxy/> </bean> <bean id="userService" class="com.wiley.beginningspring.ch7.UserService"> <property name="loginAction" ref="loginAction"/> <property name="userPreferences" ref="userPreferences"/> </bean></beans>
然后子测试类中验证了注入的依赖:
@RunWith(SpringJUnit4ClassRunner.class)@WebAppConfiguration@ContextConfiguration("classpath:/applicationContext.xml")public class ScopedBeanTests { @Autowired private UserService userService; @Autowired private MockHttpServletRequest httpServletRequest; @Autowired private MockHttpSession httpSession; @Test public void testScopedBeans() { httpServletRequest.setParameter("username", "jdoe"); httpServletRequest.setParameter("password", "secret"); httpSession.setAttribute("theme", "blue"); Assert.assertEquals("jdoe",userService.getLoginAction().getUsername()); Assert.assertEquals("secret", userService.getLoginAction().getPassword()); Assert.assertEquals("blue", httpSession.getAttribute("theme")); }}
测试Spring MVC项目
该项目需要的maven依赖如下:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.springframework.samples.service.service</groupId> <artifactId>SpringAOPTest</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>war</packaging> <properties> <!-- Generic properties --> <java.version>1.6</java.version> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <!-- Web --> <jsp.version>2.3.1</jsp.version> <jstl.version>1.2</jstl.version> <servlet.version>3.1.0</servlet.version> <!-- Spring --> <spring-framework.version>4.3.10.RELEASE</spring-framework.version> <!-- Hibernate / JPA --> <hibernate.version>5.2.10.Final</hibernate.version> <!-- Logging --> <logback.version>1.2.3</logback.version> <slf4j.version>1.7.25</slf4j.version> <!-- Test --> <junit.version>4.12</junit.version> <!-- AspectJ --> <aspectj.version>1.8.10</aspectj.version> <!-- JSON Evaluation --> <jackson.version>2.9.0</jackson.version> <!-- Validator --> <hibernate-validator.version>6.0.2.Final</hibernate-validator.version> <javax-validation.version>2.0.0.Final</javax-validation.version> </properties> <dependencies> <!-- Spring MVC --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring-framework.version}</version> </dependency> <!-- Other Web dependencies --> <dependency> <groupId>javax.servlet</groupId> <artifactId>jstl</artifactId> <version>${jstl.version}</version> </dependency> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>${servlet.version}</version> <scope>provided</scope> </dependency> <dependency> <groupId>javax.servlet.jsp</groupId> <artifactId>javax.servlet.jsp-api</artifactId> <version>${jsp.version}</version> <scope>provided</scope> </dependency> <!-- Spring and Transactions --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring-framework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring-framework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring-framework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>${spring-framework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring-framework.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring-framework.version}</version> </dependency> <!-- Logging with SLF4J & LogBack --> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-api</artifactId> <version>${slf4j.version}</version> <scope>compile</scope> </dependency> <dependency> <groupId>ch.qos.logback</groupId> <artifactId>logback-classic</artifactId> <version>${logback.version}</version> <scope>runtime</scope> </dependency> <!-- Hibernate --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-entitymanager</artifactId> <version>${hibernate.version}</version> </dependency> <!-- Test Artifacts --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring-framework.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> <!-- AspectJ --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>${aspectj.version}</version> </dependency> <!-- JSON Evaluation --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-core</artifactId> <version>${jackson.version}</version> </dependency> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>${jackson.version}</version> </dependency> <!-- Validator --> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-validator</artifactId> <version>${hibernate-validator.version}</version> </dependency> <dependency> <groupId>javax.validation</groupId> <artifactId>validation-api</artifactId> <version>${javax-validation.version}</version> </dependency> <!-- https://mvnrepository.com/artifact/org.hamcrest/hamcrest-all --> <dependency> <groupId>org.hamcrest</groupId> <artifactId>hamcrest-all</artifactId> <version>1.3</version> <scope>test</scope> </dependency> <!-- https://mvnrepository.com/artifact/javax.el/javax.el-api --> <dependency> <groupId>javax.el</groupId> <artifactId>javax.el-api</artifactId> <version>3.0.0</version> </dependency> <!-- https://mvnrepository.com/artifact/org.glassfish/javax.el --> <dependency> <groupId>org.glassfish</groupId> <artifactId>javax.el</artifactId> <version>3.0.0</version> </dependency> <dependencies> </project>
项目目录结构如下:
首先创建项目所需要的User和simpleUser域类。
public class User { @Size(min=3, max=20) String username; @Email String email; @CreditCardNumber String ccNumber; @Pattern(regexp = "^[a-zA-Z]\\w{3,14}$") String password; public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getCcNumber() { return ccNumber; } public void setCcNumber(String ccNumber) { this.ccNumber = ccNumber; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; }}public class SimpleUser { private String name; private String lastName; public SimpleUser() { } public SimpleUser(String name, String lastName) { this.name = name; this.lastName = lastName; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; }}
然后创造查找失败抛出的异常类。
public class UserNotFoundException extends Exception { public UserNotFoundException(String name) { super("User not found with name: " + name); }}
然后创建一个简单的控制器。
@Controllerpublic class HelloReaderController { @RequestMapping(value = "/hello") public ModelAndView sayHello() { ModelAndView mv = new ModelAndView(); mv.addObject("message", "Hello Reader!"); mv.setViewName("helloReader"); return mv; }}
为方便测试,创建一个加载上下文的基类,之后的所有测试类都继承该类从而继承上下文配置。
@RunWith(SpringJUnit4ClassRunner.class)@WebAppConfiguration@ContextConfiguration("file:src/main/webapp/WEB-INF/springmvc-servlet.xml")public abstract class BaseControllerTests {}
其中上下文配置文件如下。
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:mvc="http://www.springframework.org/schema/mvc" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd"> <context:component-scan base-package="com.lonelyquantum.wileybookch7" /> <context:annotation-config /> <mvc:annotation-driven validator="validator" /> <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"> <property name="prefix" value="/WEB-INF/pages/" /> <property name="suffix" value=".jsp" /> </bean> <bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean" /></beans>
创建测试简单控制器的测试类。
public class HelloReaderControllerTests extends BaseControllerTests { @Autowired private WebApplicationContext wac; private MockMvc mockMvc; @Before public void setup() { this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); } @Test public void helloReaderControllerWorksOk() throws Exception { mockMvc.perform(get("/hello")) .andExpect(status().isOk()) .andDo(print()) .andExpect(model().attribute("message", "Hello Reader!")) .andExpect(view().name("helloReader")); } @Test public void helloReaderControllerWorksOkWithAnUnmappedUrl() throws Exception { mockMvc.perform(post("/helloMyLove")) .andExpect(status().isNotFound()); }}
测试中使用MockMvc类来进行控制器测试。可以看见该类可以发送http请求并测试返回值是否符合预期。测试通过。
然后创建表单提交控制类。
@Controllerpublic class UserController { @RequestMapping(value = "/result") public ModelAndView processUser(@Valid User user, BindingResult result) { ModelAndView modelAndView = new ModelAndView(); modelAndView.addObject("u", user); if (result.hasErrors()) { modelAndView.setViewName("userForm"); } else { modelAndView.setViewName("userResult"); } return modelAndView; }}
和它的测试类。
public class UserControllerTests extends BaseControllerTests { @Autowired private WebApplicationContext wac; private MockMvc mockMvc; @Before public void setup() { this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); } @Test public void formSubmittedSuccessfully() throws Exception { this.mockMvc.perform( post("/result") .param("username", "johndoe") .param("email", "john@doe.com") .param("ccNumber", "5245771326014172") .param("password", "TestR0ck")) .andExpect(status().isOk()) .andExpect(view().name("userResult")) .andExpect(model().hasNoErrors()) .andExpect(model().attribute("u", hasProperty("username", is("johndoe")))) .andExpect(model().attribute("u", hasProperty("email", is("john@doe.com")))) .andExpect(model().attribute("u", hasProperty("ccNumber", is("5245771326014172")))) .andExpect(model().attribute("u", hasProperty("password", is("TestR0ck")))); } @Test public void formSubmittedSuccessfullyButContainsValidationErrors() throws Exception { this.mockMvc.perform( post("/result") .param("username", "ok")) .andExpect(status().isOk()) .andExpect(view().name("userForm")) .andExpect(model().hasErrors()); }}
该测试类中通过param加入了输入变量作为提交表单的内容,然后用同样的方法测试返回值。测试通过。
最后创建异常处理类。
@Controllerpublic class User2Controller { private Map<String, SimpleUser> users = new HashMap<String, SimpleUser>(); @PostConstruct public void setup() { users.put("mert", new SimpleUser("Mert", "Caliskan")); users.put("kenan", new SimpleUser("Kenan", "Sevindik")); } @RequestMapping(value = "/findUser") public ModelAndView processUser(String name) throws Exception { ModelAndView modelAndView = new ModelAndView(); SimpleUser user = users.get(name); if (user == null) { throw new UserNotFoundException(name); } modelAndView.addObject("u", user); modelAndView.setViewName("userResult"); return modelAndView; } @ExceptionHandler(UserNotFoundException.class) public ModelAndView handleException(UserNotFoundException e) { ModelAndView modelAndView = new ModelAndView("errorUser"); modelAndView.addObject("errorMessage", e.getMessage()); return modelAndView; }}
和它的测试类。
public class User2ControllerTests extends BaseControllerTests { @Autowired private WebApplicationContext wac; private MockMvc mockMvc; @Before public void setup() { this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build(); } @Test public void userNotFoundExceptionHandledSuccessfully() throws Exception { this.mockMvc.perform(get("/findUser").param("name", "johndoe")) .andExpect(status().isOk()) .andExpect(view().name("errorUser")) .andExpect(model().attribute("errorMessage", "User not found with name: johndoe")); }}
测试通过。
- Beginning Spring学习笔记——第7章 使用Spring进行测试驱动开发
- Beginning Spring学习笔记——第6章(二)使用Spring进行声明式事务管理
- Beginning Spring学习笔记——第6章(三)使用Spring进行编程式事务管理
- Beginning Spring学习笔记——第11章 使用Spring开发REST风格的Web服务
- Beginning Spring学习笔记——第1章
- Beginning Spring学习笔记——第9章 SpEL
- Beginning Spring学习笔记——第10章 缓存
- Beginning Spring学习笔记——第4章(二)使用Spring执行数据访问操作
- Beginning Spring学习笔记——第2章(一)Spring IoC容器
- Beginning Spring学习笔记——第2章(三)Spring的Bean管理
- Beginning Spring学习笔记——第3章(一)Spring MVC基础
- Beginning Spring学习笔记——第4章(一)Spring JDBC连接的配置
- Beginning Spring学习笔记——第5章(二)Spring的JPA支持
- Beginning Spring学习笔记——第6章(一)Spring事务管理基础
- Beginning Spring学习笔记——第8章 Spring AOP
- 使用Spring进行测试驱动开发
- Beginning Spring学习笔记——第2章(二)依赖注入
- Beginning Spring学习笔记——第3章(二)表单处理
- 设计模式
- Distribute Candies
- linux 命令
- MessageBodyProviderNotFoundException,ModelValidationException
- Tabl栏效果的实现
- Beginning Spring学习笔记——第7章 使用Spring进行测试驱动开发
- 安装jdk后出现bash: ./java: /lib/ld-linux.so.2: bad ELF interpreter
- mybatis与spring的整合
- CodeForce 681C 模拟题
- Java正则表达式实例
- 线程安全的单例模式
- 2017微软中国社招C++研发岗面试经历(共5面)
- 面向服务与微服务架构
- 学习使我快乐