这节主要介绍Service层和Web层介绍.
Service层测试:
方案1 :利用Mock 对象
@SpringApplicationContext( {"baobaotao-dao.xml","baobaotao-service.xml" })
public class UserServiceTest extends UnitilsJUnit4 {
@SpringBean("userService")
private UserService userService;
// mock 模拟对象
private UserDao userDao;
private LoginLogDao loginLogDao;
@Before
public void init(){
userDao = mock(UserDao.class);
loginLogDao = mock(LoginLogDao.class);
}
@Test
public void hasMatchUser() {
User user = new User();
user.setUserName("tom");
user.setPassword("1234");
user.setCredits(100L);
doReturn(1).when(userDao).getMatchCount("tom", "1234");
UserServiceImpl userService = new UserServiceImpl();
ReflectionTestUtils.setField(userService, "userDao", userDao);
boolean isMatch = userService.hasMatchUser("tom", "1234");
assertThat(isMatch,is(true));
verify(userDao,times(1)).getMatchCount("tom", "1234");
}
@Test
// 只想测试service 层的功能 利用mock 不用连接数据库就可以进行sevice层测试
public void findUserByUserName() {
User user = new User();
user.setUserName("tom");
user.setPassword("1234");
user.setCredits(100L);
doReturn(user).when(userDao).findUserByUserName("tom");
UserServiceImpl userService = new UserServiceImpl();
// 设置UserService 属性 一个访问测试对象中私有属性非常好的工具类
ReflectionTestUtils.setField(userService, "userDao", userDao);
User u = userService.findUserByUserName("tom");
assertNotNull(u);
assertThat(u.getUserName(),equalTo(user.getUserName()));
// 验证findUserByUserName被调用的次数
verify(userDao,times(1)).findUserByUserName("tom");
}
利用Mock 对象,模拟DAO层的访问,通过设置其返回对象模拟数据库访问操作。这时候是不需要连接数据库和加载数据上下文的,只是通过mock对象测试Service业务逻辑的正确性。
方案2:加载Spring 上下文,利用Excel准备测试数据。
<span style="white-space:pre"> </span>@Test
@DataSet("BaobaoTao.SaveUsers.xls")// 通过读取xls 准备测试数据
public void loginSuccess() {
User user = userService.findUserByUserName("tom");
Date now = new Date();
user.setLastVisit(now);
userService.loginSuccess(user);
User u = userService.findUserByUserName("tom");
assertThat(u.getCredits(),is(105L));
}
@DataSet注解将解析Excel数据插入到数据库,通过@SpringBean("userService") private UserService userService;从应用上下文中加载,然后调用severic方法,测试业务逻辑的正确性,这时候DAO层进行了实际的数据库访问。这是时候需要加载Spring 应用上下文和配置文件,其配置文件省略介绍。
Web层测试:
Spring在org.springframework.mock包中为一些依赖于容器的接口提供了模拟类,这样可以在不启动容器的情况下执行单元测试,提高测试运行效率,模拟类包含以下包:
1、org.springframework.mock.jndi JNDI SPI接口提供的模拟类
2、org.springframework.mock.web servelt API 接口(HttpServletRequest、ServletContext),可以脱离servlet容器进行测试。
3、org.springframework.mock.web.portlet
首先测试前提,一个Spring MVC 下的登录操作,Web层代码如下:
@Controller
public class LoginController{
@Autowired
private UserService userService;
//②负责处理/index.html的请求
@RequestMapping(value = "/index.html")
public String loginPage(){
return "login";
}
//③负责处理/loginCheck.html的请求
@RequestMapping(value = "/loginCheck.html")
public ModelAndView loginCheck(HttpServletRequest request){
User user = new User();
user.setUserName(request.getParameter("userName"));
user.setPassword(request.getParameter("password"));
boolean isValidUser =
userService.hasMatchUser(user.getUserName(),
user.getPassword());
if (!isValidUser) {
return new ModelAndView("login", "error", "用户名或密码错误。");
} else {
user = userService.findUserByUserName(user
.getUserName());
user.setLastIp(request.getLocalAddr());
user.setLastVisit(new Date());
userService.loginSuccess(user);
request.getSession().setAttribute("user", user);
return new ModelAndView("main");
//ModelAndView mv = new ModelAndView("xStreamMarshallingView");
//mv.addObject(user);
//return mv;
}
}
}
其中涉及到jsp文件和配置文件省略介绍。
1、使用Spring Servlet API 模拟对象
@SpringApplicationContext( { "classpath:applicationContext.xml",
"file:webapp/WEB-INF/baobaotao-servlet.xml" })
public class LoginControllerTest extends UnitilsJUnit4 {
// ① 从Spring容器中加载AnnotationMethodHandlerAdapter
@SpringBeanByType
private AnnotationMethodHandlerAdapter handlerAdapter;
// ② 从Spring容器中加载LoginController
@SpringBeanByType
private LoginController controller;
@SpringBeanByType
private RestTemplate restTemplate;
// ③ 声明Request与Response模拟对象
private MockHttpServletRequest request;
private MockHttpServletResponse response;
// ④ 执行测试前先初始模拟对象
@Before
public void before() {
request = new MockHttpServletRequest();
request.setCharacterEncoding("UTF-8");
response = new MockHttpServletResponse();
}
// ⑤ 测试LoginController#loginCheck()方法
@Test
public void loginCheckByMock() throws Exception {
request.setRequestURI("/loginCheck.html");
request.addParameter("userName", "tom"); // ⑥ 设置请求URL及参数
request.addParameter("password", "1234");
// ⑦ 向控制发起请求 ” /loginCheck.html”
ModelAndView mav = handlerAdapter.handle(request, response, controller);
User user = (User) request.getSession().getAttribute("user");
assertNotNull(mav);
assertEquals(mav.getViewName(), "main");
assertNotNull(user);
assertThat(user.getUserName(), equalTo("tom"));// ⑧ 验证返回结果
assertThat(user.getCredits(), greaterThan(5L));
}
}
加载Spring 和servlet上下文,在配置文件中需要配置
<bean id="defaultAnnotationHandlerMapping"
class="org.springframework.web.servlet.mvc.annotation.DefaultAnnotationHandlerMapping" />
<bean id="annotationMethodHandlerAdapter"
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" />
通过注入handlerAdapter获取实例,利用MockHttpServletRequest和MockHttpServletResponse模拟类模拟request 和response操作。
这时不需要启动Servlet容器。
2、Spring RestTemplate 测试:
RestTemplate是利用在客户端访问WEB服务的类。
利用RestTemplate得现在Spring配置文件中配置:
<bean id="restTemplate" class="org.springframework.web.client.RestTemplate">
<!--配置消息转换器-->
<property name="messageConverters">
<list>
<bean id="stringHttpMessageConverter"
class="org.springframework.http.converter.StringHttpMessageConverter" />
<bean id="formHttpMessageConverter"
class="org.springframework.http.converter.FormHttpMessageConverter" />
</list>
</property>
</bean>
配置了两个消息转化器。
其测试代码如下:
@Test
public void loginCheck() {
//MultiValueMap是Map的一种实现形式,它最大的特定是可以为一个key对应多个value
MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
map.add("userName", "john");
map.add("password", "1234");
String result = restTemplate.postForObject(
"http://localhost/chapter16/loginCheck.html", map, String.class);
assertNotNull(result);
assertThat(result, containsString("用户名或密码错误"));
map.clear();
map.add("userName", "tom");
map.add("password", "1234");
result = restTemplate.postForObject(
"http://localhost/chapter16/loginCheck.html", map, String.class);
System.out.println(result);
assertNotNull(result);
assertThat(result, containsString("tom,欢迎您进入宝宝淘论坛"));
}
这是需要启动Web容器进行测试。
3、使用Selenium 测试
Selenium 是模拟用户对视图在不同浏览器中的操作正确性的测试,这也是WEB测试的重点和难点,支持Firefox,IE,Opear,Chrome等主要浏览器,通过加载不同浏览器的web测试驱动器来测试视图在不同浏览器下的正确性。这里不做介绍了。