`
hawkist
  • 浏览: 35944 次
  • 性别: Icon_minigender_1
  • 来自: 成都
文章分类
社区版块
存档分类
最新评论

tdd小结

阅读更多
    以前我写测试代码的时候,一直有个误区,对某类某方法的测试,有严重的依赖性,比如在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 静态方法生成
   
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).pdf

    本文档详细介绍了TDD-LTE无线网络优化案例(2),其中包括测试环境、优化前覆盖情况、优化思路及方案、优化后覆盖情况和优化小结等部分。 测试环境:鼎利ATU路测设备、DTAS分析软件、桐乡大道中环西路周边路段测试...

    软件工具与环境实验报告

    **实验小结** - 通过本次实验,学生可以掌握Eclipse的基本操作,如切换透视图、编写和调试Java程序等。 - 这对于进一步学习Java编程和使用Eclipse进行项目开发非常重要。 #### 实验二:用TDD模式开发求N的阶乘程序 ...

    实训note笔记实用

    ### 小结 实训note笔记不仅涵盖了TDD、Java、JSP和UML等关键知识点,还深入探讨了它们的实际应用和最佳实践。对于初学者和专业人士来说,这些笔记是宝贵的参考资料,能够帮助他们深化对IT领域的理解和掌握。通过...

    面向对象分析与设计:关于过程的话题

    5.4 本章小结 本章阐述了面向对象开发中过程的重要性,介绍了三种主流的软件开发过程,强调了它们如何帮助团队有效地管理复杂项目,提升软件质量和适应性。无论是RUP的迭代模型,还是TDD和XP的实践导向,都是为了在...

    《3GPP长期演进(LTE)技术原理与系统设计》part2

    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 ...

    毕业论文全双工通信中的自干扰消除技术.doc

    * 小结:天线干扰消除技术是全双工通信中的一个重要组成部分,可以有效地消除自干扰信号,提高系统的可靠性和速度。 三、射频干扰消除 * 射频消除概念:射频干扰消除技术是使用射频信号来消除自干扰信号,从而提高...

    《3GPP长期演进(LTE)技术原理与系统设计》Part1

    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物理层的设计旨在确保高效的数据传输和良好的用户体验。通过精确的时隙和帧结构定义,LTE能够支持不同的双工模式,并为不同类型的业务提供灵活的资源配置。此外,物理信道和信号的设计也考虑了信号...

    蓝牙微微网内主节点调度算法的研究

    #### 小结 本文深入探讨了蓝牙Piconet内主节点调度算法的研究,通过对传统循环法的缺陷分析,引入了公平耗尽循环法(FEP)和最大最小公平份额分配与差额循环调度法(DR),并通过仿真对比展示了这些算法的有效性和...

    2单元测试基础.pptx

    ### 小结 单元测试是软件开发流程中的一项核心技能,它不仅有助于提升代码的质量,还能促进团队之间的协作和沟通。通过遵循良好的单元测试实践,如使用单元测试框架、编写可读性强的测试代码以及定期重构,开发者...

    移动通信第12章_B3G与4G移动通信系统.pptx

    12.7 本章小结 这一章总结了B3G与4G移动通信系统的主要技术特点和标准演进过程,包括从IMT-2000的提出到4G IMT-Advanced的需求定义,以及各种技术如HSPA、EV-DO、LTE和WiMax在这一过程中扮演的角色。 总体来说,...

    通信TD优化

    #### 小结 TD-SCDMA作为一种先进的第三代移动通信标准,其物理层的设计充分考虑了高速数据传输的需求,采用了多项关键技术来提高通信质量和系统的整体性能。通过深入研究TD-SCDMA物理层原理,不仅可以帮助我们更好...

    TD-SCDMA培训教材

    ### 小结 《TD-SCDMA培训教材》不仅是一份详尽的技术指南,更是TD-SCDMA网络规划与优化实践的宝典。通过对TD-SCDMA关键技术、设备特性和规划流程的深度解析,读者能够全面掌握TD-SCDMA网络的设计原理和实施技巧,为...

    软件测试系列最佳实践

    - **4.4 小结**:总结了测试用例设计的重要性和方法,强调了设计高质量测试用例对于确保软件质量的关键作用。 #### 第5章 从虚拟测试环境到一键部署 第五章探讨了如何构建高效的测试环境和自动化部署流程,以支持...

Global site tag (gtag.js) - Google Analytics