首先创建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.0modelVersion>
<groupId>com.lonelyquantum.springbeginning.wileybookch4groupId>
<artifactId>JDBCTestartifactId>
<version>0.0.1-SNAPSHOTversion>
<packaging>jarpackaging>
<name>JDBCTestname>
<url>http://maven.apache.orgurl>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<spring.version>4.3.10.RELEASEspring.version>
<junit.version>4.12junit.version>
properties>
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>${junit.version}version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-testartifactId>
<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 accounts);
public void delete(long accountId);
public Account find(long accountId);
public List find(List accountIds);
public List find(String ownerName);
public List find(boolean locked);
}
public class AccountDaoInMemoryImpl implements AccountDao {
private Map accountsMap = new HashMap<>();
public void setAccountsMap(Map 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 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 find(List accountIds) {
List accounts = new ArrayList<>();
for(Long id:accountIds) {
accounts.add(accountsMap.get(id));
}
return accounts;
}
@Override
public List find(String ownerName) {
List accounts = new ArrayList<>();
for(Account account:accountsMap.values()) {
if(ownerName.equals(account.getOwnerName())) {
accounts.add(account);
}
}
return accounts;
}
@Override
public List find(boolean locked) {
List 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配置文件。
<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。
@Configuration
public 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。
<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>
接着创建子配置文件。
<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);
}
}
运行孩子测试类通过,说明孩子测试类继承了基础测试类的配置文件。
如果多个测试类指定了完全相同的XML位置和配置类,那么Spring TestContext Framework将只创建一次ApplicatoinContext实例,并在运行这些测试类之间共享该实例。
缓存被保存再一个静态变量中。
public class Bar {
}
public class Foo {
}
然后创建测试类:
@Configuration
public 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的依赖文件:
<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.0modelVersion>
<groupId>com.lonelyquantum.springbeginning.wileybookch4groupId>
<artifactId>JDBCTestartifactId>
<version>0.0.1-SNAPSHOTversion>
<packaging>jarpackaging>
<name>JDBCTestname>
<url>http://maven.apache.orgurl>
<properties>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<spring.version>4.3.10.RELEASEspring.version>
<junit.version>4.12junit.version>
<javax.servlet.version>3.1.0javax.servlet.version>
properties>
<dependencies>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>${junit.version}version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-testartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webartifactId>
<version>${spring.version}version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>${javax.servlet.version}version>
dependency>
dependencies>
project>
测试的目录结构为:
首先创建空的XML配置文件applicationContext.xml:
<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")
@WebAppConfiguration
public 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项目。运行测试成功通过。
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并注入了依赖:
<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"));
}
}
该项目需要的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.0modelVersion>
<groupId>org.springframework.samples.service.servicegroupId>
<artifactId>SpringAOPTestartifactId>
<version>0.0.1-SNAPSHOTversion>
<packaging>warpackaging>
<properties>
<java.version>1.6java.version>
<project.build.sourceEncoding>UTF-8project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8project.reporting.outputEncoding>
<jsp.version>2.3.1jsp.version>
<jstl.version>1.2jstl.version>
<servlet.version>3.1.0servlet.version>
<spring-framework.version>4.3.10.RELEASEspring-framework.version>
<hibernate.version>5.2.10.Finalhibernate.version>
<logback.version>1.2.3logback.version>
<slf4j.version>1.7.25slf4j.version>
<junit.version>4.12junit.version>
<aspectj.version>1.8.10aspectj.version>
<jackson.version>2.9.0jackson.version>
<hibernate-validator.version>6.0.2.Finalhibernate-validator.version>
<javax-validation.version>2.0.0.Finaljavax-validation.version>
properties>
<dependencies>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webmvcartifactId>
<version>${spring-framework.version}version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>jstlartifactId>
<version>${jstl.version}version>
dependency>
<dependency>
<groupId>javax.servletgroupId>
<artifactId>javax.servlet-apiartifactId>
<version>${servlet.version}version>
<scope>providedscope>
dependency>
<dependency>
<groupId>javax.servlet.jspgroupId>
<artifactId>javax.servlet.jsp-apiartifactId>
<version>${jsp.version}version>
<scope>providedscope>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-txartifactId>
<version>${spring-framework.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-aopartifactId>
<version>${spring-framework.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-coreartifactId>
<version>${spring-framework.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-beansartifactId>
<version>${spring-framework.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>${spring-framework.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-webartifactId>
<version>${spring-framework.version}version>
dependency>
<dependency>
<groupId>org.slf4jgroupId>
<artifactId>slf4j-apiartifactId>
<version>${slf4j.version}version>
<scope>compilescope>
dependency>
<dependency>
<groupId>ch.qos.logbackgroupId>
<artifactId>logback-classicartifactId>
<version>${logback.version}version>
<scope>runtimescope>
dependency>
<dependency>
<groupId>org.hibernategroupId>
<artifactId>hibernate-entitymanagerartifactId>
<version>${hibernate.version}version>
dependency>
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-testartifactId>
<version>${spring-framework.version}version>
<scope>testscope>
dependency>
<dependency>
<groupId>junitgroupId>
<artifactId>junitartifactId>
<version>${junit.version}version>
<scope>testscope>
dependency>
<dependency>
<groupId>org.aspectjgroupId>
<artifactId>aspectjweaverartifactId>
<version>${aspectj.version}version>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-coreartifactId>
<version>${jackson.version}version>
dependency>
<dependency>
<groupId>com.fasterxml.jackson.coregroupId>
<artifactId>jackson-databindartifactId>
<version>${jackson.version}version>
dependency>
<dependency>
<groupId>org.hibernategroupId>
<artifactId>hibernate-validatorartifactId>
<version>${hibernate-validator.version}version>
dependency>
<dependency>
<groupId>javax.validationgroupId>
<artifactId>validation-apiartifactId>
<version>${javax-validation.version}version>
dependency>
<dependency>
<groupId>org.hamcrestgroupId>
<artifactId>hamcrest-allartifactId>
<version>1.3version>
<scope>testscope>
dependency>
<dependency>
<groupId>javax.elgroupId>
<artifactId>javax.el-apiartifactId>
<version>3.0.0version>
dependency>
<dependency>
<groupId>org.glassfishgroupId>
<artifactId>javax.elartifactId>
<version>3.0.0version>
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);
}
}
然后创建一个简单的控制器。
@Controller
public 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 {
}
其中上下文配置文件如下。
<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请求并测试返回值是否符合预期。测试通过。
然后创建表单提交控制类。
@Controller
public 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", "[email protected]")
.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("[email protected]"))))
.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加入了输入变量作为提交表单的内容,然后用同样的方法测试返回值。测试通过。
最后创建异常处理类。
@Controller
public class User2Controller {
private Map users = new HashMap();
@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"));
}
}
测试通过。