开发中的单元测试

由于对Dao层的测试时间成本相对来说比较大,而Dao层本来就没有复杂的逻辑所以在这选了Service和Controller层的单元测试.

基于Spring的单元测试库Spring-Test

这对于在用Spring的亲们应该不陌生, SpringTest可以在单元测试中初始化Spring的上下文, 这一点就已经相当方便了.

通过

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath*:applicationContext.xml")

这两个注解就可以实现, Spring的配置文件应该放在classpath中. Maven的就放在test文件夹中的resources文件夹中.

注意:

我曾经遇到过有朋友会将HttpSesson或者ServletContext注入到Service中.

@Autowired
HttpSession session;
@Autowired
ServletContext context;

这样用起来虽然简单, 但是会给单元测试造成困难. 原因: session和servletContext都是在服务器启动时创建, 而单元测试并没有去启动服务器所以Spring是没有办法去注入这两个东西的. 而且(个人经验)这种写法并不符合常规,我们可以通过Controller层去获取然后传入到Service层中, 我暂时还没有找到在单元测试注入到Spring容器的方法. (由于上面用的注解注入, 用setter并不能解决问题, 去掉注解则会造成代码污染.) 如果一定要用到的~只要不使用注解的方法去注入,然后加上setter都可以让spring成功初始化,在测试用到时通过setter注入就可以.

Service层.

在工作的时候,我也只是用SpringTest初始化容器,然后调用一下Service的方法这样去测试,但是这样的测试当遇到错误时,我们还需要去考虑到底是Service的错还是Dao层的问题.而且Spring去初始化用时非常长,花这么多时间去做一个单元测试并不是太合理. 这里我们可以使用EasyMock去构造一个Dao层方法的Mock对象, 录制所需要的执行的方法并在Service层中回放.下面我大概说说用法.

private BaseDAO<Admin> adminBaseDao;
//需要通过setter方法注入到Service中
//在测试方法中
EasyMock.createMock(BaseDAO.class);
EasyMock.expect(adminBaseDao.get("from Admin a where a.phone=? and a.password=?", 
new Object[]{"110","123"})).andReturn(result);
EasyMock.replay(adminBaseDao);

测试Service层的时候其实已经没有必要去初始化Spring了,

至于注入到Service 方法1:可以直接new一个~然后通过setter将用到的mock出来的Dao注入进去.

方法2:使用Unitils中的Inject模块使用@InjectInto注解就可以不用添加setter方法

@TestedObject
private AdminService adminService;

@Mock
@InjectInto(target = "adminService", property = "adminBaseDao")
private BaseDAO<Admin> adminBaseDao;

这样去测试Service层的好处是, Dao层的方法都是自己模拟出来的, 如果Service操作指定的数据是正常的那么当出现问题的时候就知道应该是Dao层的问题. 而且跳过了Spring初始化, 那个速度真的快了超多.

对于Controller层

使用Struts2的小伙伴可以使用Struts2的 Struts2Test的模块

public class AdminActionTest extends StrutsSpringJUnit4TestCase
注意:@Before的方法名不能用setUp. 根据JUnit3 初始化方法会使用setUp作为方法名,但是在这里Struts2Test在源码里面已经有这个setUp方法, 你在写一个会覆盖他的方法, 导致request和response无法mock出来.

贴段Struts2Test源代码:

@Before
public void setUp() throws Exception {
    super.setUp();
    this.initServletMockObjects();
    this.setupBeforeInitDispatcher();
    this.initDispatcherParams();
    this.initDispatcher(this.dispatcherInitParams);
}

在测试时按上面EasyMock的方法将Service Mock出来, 然后再通过setter或者Unitils inject 注入到Action里面, 然后需要用ActionProxy来注入…(在里面有一个executeAction的方法可以直接执行Action,如果是通过初始化Spring来测试的就可以使用,但是这样没办法注入MockService), 因为ActionProxy并不是通过request来获取参数的, 所以参数用到的对象也应该用setter或者inject 注入到Action中.

ActionProxy proxy = getActionProxy("/admin/login.action");
AdminAction action = ((AdminAction) proxy.getAction()).setAdminService(adminService);
action.setAdmin(admin);
action.setSession(request.getSession());
String result = proxy.execute();
Assert.assertEquals("success", result);

如果是使用SpringMVC的朋友其实道理都是一样的.都是Mock这个注入进去, Mock那个注入进去, SpringMVC的,mock request和mock response需要自己去创建, 直接上代码了;

private MockHttpServletRequest request = new MockHttpServletRequest();
private MockHttpServletResponse response = new MockHttpServletResponse();

@Before
public void setup() {
    awardControler = new AwardControler();
    awardService = EasyMock.createMock(AwardService.class);
    awardControler.setAwardService(awardService);
}

@Test
public void testGetAwardDetail() throws Exception {
    //create mock return object
    Award award = new Award();
    award.setId("1");
    award.setName("测试1");
    award.setStatus("未发放");
    request.setRequestURI("/awardController/getAwardDetail.do");
    request.setMethod(HttpMethod.POST.name());
    request.setParameter("id", "1");
    EasyMock.expect(awardService.getAwardById("1")).andReturn(award);
    EasyMock.expect(awardService.getAwardStatusJSON()).andReturn("ok");
    EasyMock.replay(awardService);
    ModelAndView modelAndView = awardControler.getAwardDetail(request, response);
    //create expect model
    Map<String, Object> expected = new HashMap<String, Object>();
    expected.put("id", "1");
    expected.put("Id", "1");
    expected.put("status", "ok");
    ModelAndViewAssert.assertViewName(modelAndView, "souche/award/detail.jsp");
    ModelAndViewAssert.assertModelAttributeValues(modelAndView, expected);
}

最后

软件测试交流群,加群qq(**644956177)**群里有技术交流和资源分享。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值