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("[email protected]");
		account1.setPassWord("1111");
		List<Account> list = new ArrayList<Account>();
		list.add(account1);
		EasyMock.expect(hibernateTemplate.find(
				"from Account where email=? and passWord=?",
				new String[]{"[email protected]","1111"})).andReturn(list).anyTimes();
		EasyMock.replay(hibernateTemplate);
		Account account = accountDao.getAccountByEmailAndPwd("[email protected]", "1111");
		EasyMock.verify(hibernateTemplate);
		Assert.assertEquals("[email protected]", 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("[email protected]");
		account.setPassWord("1111");
		EasyMock.expect(accountDao.getAccountByEmailAndPwd("[email protected]", "1111")).andReturn(account).anyTimes();
		EasyMock.replay(accountDao);
		Assert.assertEquals("[email protected]", accountService.getAccountByEmailAndPwd("[email protected]", "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", "[email protected]");
		request.setParameter("passWord", "1111");
		Account account = new Account();
		account.setEmail("[email protected]");
		account.setPassWord("1111");
		EasyMock.expect(accountService.getAccountByEmailAndPwd("[email protected]", "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());
	}
}

你可能感兴趣的:(cms,Web,TDD,JUnit,Nokia)