以前我写测试代码的时候,一直有个误区,对某类某方法的测试,有严重的依赖性,比如在spring中测试server层某类时,会直接引入配置文件,注入相关类进行测试,这样的结果是代码换个环境,测试代码可能无法编译通过,后来才渐渐明白,测试代码应模拟出完全空白的环境,用EasyMock和Assert的方式进行测试。
why TDD?
Avoid overdesigning;
Find problems early in development process;
Write just the code you need;
Know when you are ready;
TDD-我的理解是测试先行,从客户体验的角度用测试用例来完成某个功能点,使用EasyMock提供的接口模拟,通过录制、回放、检查三步来完成大体的测试过程,可以验证方法的调用种类、次数、顺序,可以令 Mock 对象返回指定的值或抛出指定异常。
第一步:使用 EasyMock 生成 Mock 对象
a、由 org.easymock.EasyMock 类提供的 createMock 静态方法生成
b、如果需要在相对复杂的测试用例中使用多个 Mock 对象,通过 IMocksControl 接口提供的 createMock 方法生成
第二步、设定 Mock 对象的预期行为和输出
第三步、将 Mock 对象切换到 Replay 状态
a、由a方式创建mork对象
b、由IMocksControl 接口提供的 createMock 方法生成mork对象
第四步、调用 Mock 对象方法进行单元测试,并用断言验证
第五步、对 Mock 对象的行为进行验证
a、由a方式创建mork对象
b、由IMocksControl 接口提供的 createMock 方法生成mork对象
第六步、为了避免生成过多的 Mock 对象,EasyMock 允许对原有 Mock 对象进行重新初始化
a、由a方式创建mork对象
b、由IMocksControl 接口提供的 createMock 方法生成mork对象
两种测试方式的对比
前一种方式,需要指定ContextConfiguration,并注入相关类
后一种方式采用EasyMock和Assert方式进行,但是在本类中提供属性的set方法。
如果希望测试某异常,本类中可抛出异常,测试中:
针对dao、service和controller的测试例子
需要依赖以下包:spring-mock--模拟MockHttpServletRequest、MockHttpServletResponse用;spring-test--ReflectionTestUtils设置属性用
dao:
service:
controller:
why TDD?
Avoid overdesigning;
Find problems early in development process;
Write just the code you need;
Know when you are ready;
TDD-我的理解是测试先行,从客户体验的角度用测试用例来完成某个功能点,使用EasyMock提供的接口模拟,通过录制、回放、检查三步来完成大体的测试过程,可以验证方法的调用种类、次数、顺序,可以令 Mock 对象返回指定的值或抛出指定异常。
第一步:使用 EasyMock 生成 Mock 对象
a、由 org.easymock.EasyMock 类提供的 createMock 静态方法生成
ResultSet mockResultSet = createMock(ResultSet.class);
b、如果需要在相对复杂的测试用例中使用多个 Mock 对象,通过 IMocksControl 接口提供的 createMock 方法生成
IMocksControl control = EasyMock.createControl(); java.sql.Connection mockConnection = control.createMock(Connection.class); java.sql.Statement mockStatement = control.createMock(Statement.class); java.sql.ResultSet mockResultSet = control.createMock(ResultSet.class);
第二步、设定 Mock 对象的预期行为和输出
expect(mockResult.close()).times(3, 5);//该方法最少被调用3次,最多被调用5次 expect(mockResult.close()).times(3);//该方法被调用3次 expect(mockResult.close()).atLeastOnce();//该方法至少被调用一次 expect(mockResult.close()).anyTimes();//该方法可以被调用任意次 expect(mockResult.close()).andReturn("My return value");//预期返回值 expect(mockResult.close()).andThrow(Throwable throwable);//抛出异常
第三步、将 Mock 对象切换到 Replay 状态
a、由a方式创建mork对象
replay(mockResultSet);
b、由IMocksControl 接口提供的 createMock 方法生成mork对象
control.replay();
第四步、调用 Mock 对象方法进行单元测试,并用断言验证
第五步、对 Mock 对象的行为进行验证
a、由a方式创建mork对象
verify(mockResultSet);
b、由IMocksControl 接口提供的 createMock 方法生成mork对象
control.verify();
第六步、为了避免生成过多的 Mock 对象,EasyMock 允许对原有 Mock 对象进行重新初始化
a、由a方式创建mork对象
reset(mockResultSet);
b、由IMocksControl 接口提供的 createMock 方法生成mork对象
control.reset();
两种测试方式的对比
import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import org.springframework.web.servlet.ModelAndView; import org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter; import com.nokia.wellness.cms.SpringConfiguration; import com.nokia.wellness.cms.persistence.entity.Account; import com.nokia.wellness.cms.web.account.AccountConstants; import com.nokia.wellness.cms.web.owner.controllers.ChangePasswordController; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { SpringConfiguration.LOCATION }) public class ChangePasswordControllerTest { @Autowired private ChangePasswordController controller; private MockHttpServletRequest request; private MockHttpServletResponse response; @Before public void setUp() throws Exception { request = new MockHttpServletRequest(); response = new MockHttpServletResponse(); } @After public void tearDown() throws Exception { request = null; response = null; } @Test public void testChangePasswordNotEmpty() { request.setMethod("POST"); request.setRequestURI(OwnerConstants.PREFIX + "/changePassword.do"); request.setParameter("oldPassword", "admin"); request.setParameter("newPassword", "admin"); Account account = new Account(); account.setUserName("admin"); request.getSession().setAttribute(AccountConstants.SESSION_LOGIN_ACCOUNT, account); ModelAndView mv = null; try { mv = new AnnotationMethodHandlerAdapter().handle(request, response, controller); assertNotNull(mv.getViewName()); assertNotNull(request.getAttribute("changePasswordResult")); } catch (Exception e) { assertNull(mv); } } }
前一种方式,需要指定ContextConfiguration,并注入相关类
import junit.framework.Assert; import static org.easymock.EasyMock.*; import org.junit.After; import org.junit.Before; import org.junit.Test; import com.google.code.morphia.Datastore; import com.nokia.wellness.cms.MongoHelper; import com.nokia.wellness.cms.SpringConfiguration; import com.nokia.wellness.cms.service.impl.AccountServiceImpl; import com.nokia.wellness.cms.service.impl.InitializeDataServiceImpl; import com.nokia.wellness.cms.service.impl.ResourceServiceImpl; import com.nokia.wellness.cms.service.impl.RoleServiceImpl; import com.nokia.wellness.cms.service.impl.UserProfileServiceImpl; public class IInitializeDataServiceTest { private InitializeDataServiceImpl initializeDataService; private IAccountService accountService; private IResourceService resourceService; private IRoleService roleService; private IUserProfileService userProfileService; private Datastore ds; private MongoHelper mongoHelper; @Before public void setUp(){ try { mongoHelper = new MongoHelper(); mongoHelper.start(); initializeDataService = new InitializeDataServiceImpl(); accountService = createMock(AccountServiceImpl.class); resourceService = createMock(ResourceServiceImpl.class); roleService = createMock(RoleServiceImpl.class); userProfileService = createMock(UserProfileServiceImpl.class); ds = createMock(Datastore.class); initializeDataService.setAccountService(accountService); initializeDataService.setResourceService(resourceService); initializeDataService.setRoleService(roleService); initializeDataService.setUserProfileService(userProfileService); initializeDataService.setDs(ds); } catch (Exception e) { e.printStackTrace(); } } @After public void tearDown(){ accountService = null; resourceService = null; roleService = null; userProfileService = null; ds = null; initializeDataService = null; mongoHelper.stop(); } @Test public void tsetInitializeData(){ //set the expect mock object expect(accountService.existAccount()).andReturn(false).anyTimes(); expect(resourceService.existResource()).andReturn(true).anyTimes(); expect(roleService.existRole()).andReturn(false).anyTimes(); expect(userProfileService.existUserProfile()).andReturn(false).anyTimes(); expect(ds.getDB()).andReturn(mongoHelper.getMongo().getDB(SpringConfiguration.MONGO_DATABASE)).anyTimes(); //set the replay mock object replay(accountService); replay(resourceService); replay(roleService); replay(userProfileService); replay(ds); initializeDataService.initializeData(); //verify the mock objects verify(accountService); verify(resourceService); verify(roleService); verify(userProfileService); verify(ds); } @Test public void testExistData(){ expect(accountService.existAccount()).andReturn(true).anyTimes(); expect(resourceService.existResource()).andReturn(false).anyTimes(); expect(roleService.existRole()).andReturn(false).anyTimes(); expect(userProfileService.existUserProfile()).andReturn(false).anyTimes(); replay(accountService); replay(resourceService); replay(roleService); replay(userProfileService); Assert.assertEquals(true, initializeDataService.existData()); verify(accountService); verify(resourceService); verify(roleService); verify(userProfileService); } }
后一种方式采用EasyMock和Assert方式进行,但是在本类中提供属性的set方法。
如果希望测试某异常,本类中可抛出异常,测试中:
@Test(expected=SomeException.class)
针对dao、service和controller的测试例子
需要依赖以下包:spring-mock--模拟MockHttpServletRequest、MockHttpServletResponse用;spring-test--ReflectionTestUtils设置属性用
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.8.2</version> </dependency> <dependency> <groupId>org.easymock</groupId> <artifactId>easymock</artifactId> <version>3.0</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-mock</artifactId> <version>2.0.8</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>3.0.5.RELEASE</version> </dependency>
dao:
package com.cpkf.notpad.dao.impl; import java.util.ArrayList; import java.util.List; import org.easymock.EasyMock; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.springframework.orm.hibernate3.HibernateTemplate; import org.springframework.test.util.ReflectionTestUtils; import com.cpkf.notpad.dao.IAccountDao; import com.cpkf.notpad.entity.Account; public class AccountDaoTest { private IAccountDao accountDao; private HibernateTemplate hibernateTemplate; @Before public void setUp(){ accountDao = new AccountDaoImpl(); hibernateTemplate = EasyMock.createMock(HibernateTemplate.class); ReflectionTestUtils.setField(accountDao, "hibernateTemplate", hibernateTemplate); } @After public void tearDown(){ accountDao = null; hibernateTemplate = null; } @Test public void testGetAccountByEmailAndPwd(){ Account account1 = new Account(); account1.setEmail("hj@163.com"); account1.setPassWord("1111"); List<Account> list = new ArrayList<Account>(); list.add(account1); EasyMock.expect(hibernateTemplate.find( "from Account where email=? and passWord=?", new String[]{"hj@163.com","1111"})).andReturn(list).anyTimes(); EasyMock.replay(hibernateTemplate); Account account = accountDao.getAccountByEmailAndPwd("hj@163.com", "1111"); EasyMock.verify(hibernateTemplate); Assert.assertEquals("hj@163.com", account.getEmail()); } }
service:
package com.cpkf.notpad.server.impl; import org.easymock.EasyMock; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.springframework.test.util.ReflectionTestUtils; import com.cpkf.notpad.dao.IAccountDao; import com.cpkf.notpad.dao.impl.AccountDaoImpl; import com.cpkf.notpad.entity.Account; import com.cpkf.notpad.server.IAccountService; public class AccountServiceImplTest { private IAccountDao accountDao; private IAccountService accountService; @Before public void setUp(){ accountService = new AccountServiceImpl(); accountDao = EasyMock.createMock(AccountDaoImpl.class); ReflectionTestUtils.setField(accountService, "accountDao", accountDao); } @After public void tearDown(){ accountDao = null; accountService = null; } @Test public void testGetAccountByEmailAndPwd(){ Account account = new Account(); account.setEmail("hj@163.com"); account.setPassWord("1111"); EasyMock.expect(accountDao.getAccountByEmailAndPwd("hj@163.com", "1111")).andReturn(account).anyTimes(); EasyMock.replay(accountDao); Assert.assertEquals("hj@163.com", accountService.getAccountByEmailAndPwd("hj@163.com", "1111").getEmail()); EasyMock.verify(accountDao); } }
controller:
package com.cpkf.notpad.controller.account; import org.easymock.EasyMock; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.springframework.mock.web.MockHttpServletRequest; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.test.util.ReflectionTestUtils; import org.springframework.web.servlet.ModelAndView; import com.cpkf.notpad.entity.Account; import com.cpkf.notpad.server.IAccountService; import com.cpkf.notpad.server.impl.AccountServiceImpl; public class LoginControllerTest { private IAccountService accountService; private LoginController loginController; private MockHttpServletRequest request; private MockHttpServletResponse response; @Before public void setUp(){ request = new MockHttpServletRequest(); response = new MockHttpServletResponse(); loginController = new LoginController(); accountService = EasyMock.createMock(AccountServiceImpl.class); ReflectionTestUtils.setField(loginController, "accountService", accountService); } @After public void tearDown(){ accountService = null; loginController = null; request = null; response = null; } @Test public void testLogin(){ request.setMethod("POST"); request.setRequestURI("/login.do"); request.setParameter("email", "hj@163.com"); request.setParameter("passWord", "1111"); Account account = new Account(); account.setEmail("hj@163.com"); account.setPassWord("1111"); EasyMock.expect(accountService.getAccountByEmailAndPwd("hj@163.com", "1111")).andReturn(account).anyTimes(); EasyMock.replay(accountService); ModelAndView modelAndView = loginController.login(request, response); EasyMock.verify(accountService); System.out.println(modelAndView.getViewName()); Assert.assertNotNull(modelAndView.getViewName()); } }
相关推荐
本文档详细介绍了TDD-LTE无线网络优化案例(2),其中包括测试环境、优化前覆盖情况、优化思路及方案、优化后覆盖情况和优化小结等部分。 测试环境:鼎利ATU路测设备、DTAS分析软件、桐乡大道中环西路周边路段测试...
9. 不区分大小写:如涉及输入,如电子邮件和搜索条件,通常不区分大小写。 10. 页面适应性:测试页面在不同窗口大小下的表现,尤其是出现滚动条的情况,确保页面布局不变形。 11. 浏览器兼容性:关注不同浏览器...
**实验小结** - 通过本次实验,学生可以掌握Eclipse的基本操作,如切换透视图、编写和调试Java程序等。 - 这对于进一步学习Java编程和使用Eclipse进行项目开发非常重要。 #### 实验二:用TDD模式开发求N的阶乘程序 ...
### 小结 实训note笔记不仅涵盖了TDD、Java、JSP和UML等关键知识点,还深入探讨了它们的实际应用和最佳实践。对于初学者和专业人士来说,这些笔记是宝贵的参考资料,能够帮助他们深化对IT领域的理解和掌握。通过...
5.4 本章小结 本章阐述了面向对象开发中过程的重要性,介绍了三种主流的软件开发过程,强调了它们如何帮助团队有效地管理复杂项目,提升软件质量和适应性。无论是RUP的迭代模型,还是TDD和XP的实践导向,都是为了在...
1.7 小结 31 参考文献 31 第2章 LTE需求 32 2.1 系统容量需求 33 2.1.1 峰值速率 33 2.1.2 系统延迟 33 2.2 系统性能需求 34 2.2.1 用户吞吐量与控制面容量 34 2.2.2 频谱效率 35 2.2.3 移动性 36 2.2.4 覆盖 36 ...
* 小结:天线干扰消除技术是全双工通信中的一个重要组成部分,可以有效地消除自干扰信号,提高系统的可靠性和速度。 三、射频干扰消除 * 射频消除概念:射频干扰消除技术是使用射频信号来消除自干扰信号,从而提高...
1.7 小结 31 参考文献 31 第2章 LTE需求 32 2.1 系统容量需求 33 2.1.1 峰值速率 33 2.1.2 系统延迟 33 2.2 系统性能需求 34 2.2.1 用户吞吐量与控制面容量 34 2.2.2 频谱效率 35 2.2.3 移动性 36 2.2.4 覆盖 36 ...
#### 小结 LTE物理层的设计旨在确保高效的数据传输和良好的用户体验。通过精确的时隙和帧结构定义,LTE能够支持不同的双工模式,并为不同类型的业务提供灵活的资源配置。此外,物理信道和信号的设计也考虑了信号...
#### 小结 本文深入探讨了蓝牙Piconet内主节点调度算法的研究,通过对传统循环法的缺陷分析,引入了公平耗尽循环法(FEP)和最大最小公平份额分配与差额循环调度法(DR),并通过仿真对比展示了这些算法的有效性和...
### 小结 单元测试是软件开发流程中的一项核心技能,它不仅有助于提升代码的质量,还能促进团队之间的协作和沟通。通过遵循良好的单元测试实践,如使用单元测试框架、编写可读性强的测试代码以及定期重构,开发者...
12.7 本章小结 这一章总结了B3G与4G移动通信系统的主要技术特点和标准演进过程,包括从IMT-2000的提出到4G IMT-Advanced的需求定义,以及各种技术如HSPA、EV-DO、LTE和WiMax在这一过程中扮演的角色。 总体来说,...
### 小结 《TD-SCDMA培训教材》不仅是一份详尽的技术指南,更是TD-SCDMA网络规划与优化实践的宝典。通过对TD-SCDMA关键技术、设备特性和规划流程的深度解析,读者能够全面掌握TD-SCDMA网络的设计原理和实施技巧,为...
- **4.4 小结**:总结了测试用例设计的重要性和方法,强调了设计高质量测试用例对于确保软件质量的关键作用。 #### 第5章 从虚拟测试环境到一键部署 第五章探讨了如何构建高效的测试环境和自动化部署流程,以支持...
### 小结 通过以上分析,我们了解到3G移动通信技术的核心内容及其在不同场景下的应用情况,并且掌握了如何使用C语言来解决实际问题。该程序虽然简单,但涵盖了变量定义、数据输入输出、数学运算等多个方面,对于初学...