最近公司一直在鼓励写单元测试,故最近自己也整理了些比较常用的单元测试用法,在这里跟大家分享!
以下便是我们经常写的一个测试类,那么其中的一些内容我们是否完全都理解呢,下面我来给大家介绍下:
package com.lyancafe.csr.bo;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import junit.framework.Assert;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mockito;
import com.lyancafe.common.Pagination;
import com.lyancafe.core.dao.CityDao;
import com.lyancafe.core.model.City;
import com.lyancafe.exception.CityExistException;
public class CityBoImplTest {
private CityBoImpl cityBoImpl;
private CityDao cityDao;
@Before
public void setUp() throws Exception {
cityBoImpl = new CityBoImpl();
cityDao = mock(CityDao.class);
setPropertyByReflect(cityBoImpl, "cityDao", cityDao);
}
@Test
public void testCreateCity() {
City city = createCity();
when(cityDao.queryCount(Mockito.anyMapOf(String.class, Object.class))).thenReturn(0);
when(cityDao.createCity(Mockito.any(City.class))).thenReturn(1);
try {
cityBoImpl.createCity(city);
} catch (CityExistException e) {
Assert.assertTrue(false);
}
verify(cityDao, times(1)).queryCount(Mockito.anyMapOf(String.class, Object.class));
verify(cityDao, times(1)).createCity(Mockito.any(City.class));
}
@Test
public void testRenameCitySuccessfully() {
City city = createCity();
//when(cityDao.queryCount(Mockito.anyMapOf(String.class, Object.class))).thenReturn(0);
when(cityDao.update(Mockito.any(City.class))).thenReturn(1);
try {
cityBoImpl.renameCity(city);
} catch (CityExistException e) {
Assert.assertTrue(false);
}
//verify(cityDao, times(1)).queryCount(Mockito.anyMapOf(String.class, Object.class));
verify(cityDao, times(1)).update(Mockito.any(City.class));
}
@Test
public void testRenameCityToAnUsedName() {
City city = createCity();
//when(cityDao.queryCount(Mockito.anyMapOf(String.class, Object.class))).thenReturn(1);
when(cityDao.update(Mockito.any(City.class))).thenReturn(1);
try {
cityBoImpl.renameCity(city);
// should get exception
//Assert.assertTrue(false);
} catch (CityExistException e) {
}
//verify(cityDao, times(1)).queryCount(Mockito.anyMapOf(String.class, Object.class));
verify(cityDao, times(1)).update(Mockito.any(City.class));
}
@Test
public void testOpenCity() {
City city = createCity();
when(cityDao.openCity(Mockito.any(City.class))).thenReturn(1);
cityBoImpl.openCity(city);
verify(cityDao, times(1)).openCity(Mockito.any(City.class));
}
@Test
public void testCloseCity() {
City city = createCity();
when(cityDao.closeCity(Mockito.any(City.class))).thenReturn(1);
cityBoImpl.closeCity(city);
verify(cityDao, times(1)).closeCity(Mockito.any(City.class));
}
@Test
public void testFindActiveCity() {
Pagination<City> pagination = new Pagination<City>();
pagination.setItemPerPage(1);
pagination.setCurPage(1);
List<City> cityList = createCityList();
when(cityDao.queryCount(Mockito.anyMapOf(String.class, Object.class))).thenReturn(cityList.size());
when(cityDao.queryCity(Mockito.anyMapOf(String.class, Object.class))).thenReturn(cityList);
pagination = cityBoImpl.findActiveCityByPage(pagination);
verify(cityDao, times(1)).queryCount(Mockito.anyMapOf(String.class, Object.class));
verify(cityDao, times(1)).queryCity(Mockito.anyMapOf(String.class, Object.class));
Assert.assertEquals(pagination.getTotalCount(), cityList.size());
Assert.assertTrue(pagination.hasNext());
}
@Test
public void testFindInactiveCity() {
Pagination<City> pagination = new Pagination<City>();
pagination.setItemPerPage(1);
pagination.setCurPage(1);
List<City> cityList = createCityList();
when(cityDao.queryCount(Mockito.anyMapOf(String.class, Object.class))).thenReturn(cityList.size());
when(cityDao.queryCity(Mockito.anyMapOf(String.class, Object.class))).thenReturn(cityList);
pagination = cityBoImpl.findInactiveCityByPage(pagination);
verify(cityDao, times(1)).queryCount(Mockito.anyMapOf(String.class, Object.class));
verify(cityDao, times(1)).queryCity(Mockito.anyMapOf(String.class, Object.class));
Assert.assertEquals(pagination.getTotalCount(), cityList.size());
Assert.assertTrue(pagination.hasNext());
}
private City createCity() {
return createCity("any city name");
}
private City createCity(String cityName) {
City city = new City();
city.setName(cityName);
return city;
}
private List<City> createCityList() {
List<City> cityList = new ArrayList<City>();
cityList.add(createCity("Shanghai"));
cityList.add(createCity("Beijing"));
cityList.add(createCity("Shenzhen"));
cityList.add(createCity("Guangzhou"));
cityList.add(createCity("Hangzhou"));
return cityList;
}
public void setPropertyByReflect(Object target, String name, Object value) throws Exception {
Field field = target.getClass().getDeclaredField(name);
field.setAccessible(true);
field.set(target, value);
}
}
在测试类中,并不是每一个方法都是用于测试的,你必须使用“标注”来明确表明哪些是测试方法。“标注”也是JDK5的一个新特性,用在此处非常恰当。我们可以看到,在某些方法的前有@Before、@Test、@Ignore等字样,这些就是标注,以一个“@”作为开头。这些标注都是JUnit4自定义的,熟练掌握这些标注的含义非常重要。
1,简单的测试类
@Test
public void testUpdate() {
DeliveryArea carryArea = carryAreaBo.findCarryAreaById(8);
if (carryArea != null) {
carryArea.setName("why");
carryArea.setCenterAddress("myaddress");
carryArea.setCenterLatitude(121.12345678901234);
carryArea.setCenterLongitude(234.09876543214321);
carryArea.setRadius(14.1234);
carryAreaBo.updateCarryArea(carryArea);
System.out.println(carryArea.getCenterLatitude());
System.out.println(carryArea.getCenterLongitude());
System.out.println(carryArea.toString());
}
}2,忽略测试某些尚未完成的方法
@Ignore
@Test
public void testUpdate() {
DeliveryArea carryArea = carryAreaBo.findCarryAreaById(8);
if (carryArea != null) {
carryArea.setName("why");
carryArea.setCenterAddress("myaddress");
carryArea.setCenterLatitude(121.12345678901234);
carryArea.setCenterLongitude(234.09876543214321);
carryArea.setRadius(14.1234);
carryAreaBo.updateCarryArea(carryArea);
System.out.println(carryArea.getCenterLatitude());
System.out.println(carryArea.getCenterLongitude());
System.out.println(carryArea.toString());
}
}3,Fixture(固定代码段的执行)
Fixture的含义就是“在某些阶段必然被调用的代码”。
其一:
比如,如果我们只声明了一个Calculator对象,他的初始值是0,但是测试完加法操作后,他的值就不是0了;接下来测试减法操作,就必然要考虑上次加法操作的结果。这绝对是一个很糟糕的设计!我们非常希望每一个测试都是独立的,相互之间没有任何耦合度。因此,我们就很有必要在执行每一个测试之前,对Calculator对象进行一个“复原”操作,以消除其他测试造成的影响。因此,“在任何一个测试执行之前必须执行的代码”就是一个Fixture,我们用@Before来标注它,如前面例子所示:
@Before
public void setUp() throws Exception {
calculator.clear();
}这里不在需要@Test标注,因为这不是一个test,而是一个Fixture。同理,如果“在任何测试执行之后需要进行的收尾工作”也是一个Fixture,使用@After来标注。由于本例比较简单,没有用到此功能。
其二:
有一个类是负责对大文件(超过500兆)进行读写,他的每一个方法都是对文件进行操作。换句话说,在调用每一个方法之前,我们都要打开一个大文件并读入文件内容,这绝对是一个非常耗费时间的操作。如果我们使用@Before和@After,那么每次测试都要读取一次文件,效率及其低下。这里我们所希望的是在所有测试一开始读一次文件,所有测试结束之后释放文件,而不是每次测试都读文件。JUnit的作者显然也考虑到了这个问题,它给出了@BeforeClass 和 @AfterClass两个Fixture来帮我们实现这个功能。从名字上就可以看出,用这两个Fixture标注的函数,只在测试用例初始化时执行@BeforeClass方法,当所有测试执行完毕之后,执行@AfterClass进行收尾工作。在这里要注意一下,每个测试类只能有一个方法被标注为@BeforeClass 或 @AfterClass,并且该方法必须是Public和Static的。
介绍:
JUnit 是单元测试框架。Mockito 与 JUnit 不同,并不是单元测试框架(这方面 JUnit 已经足够好了),它是用于生成模拟对象或者直接点说,就是”假对象“的工具。两者定位不同,所以一般通常的做法就是联合 JUnit + Mockito 来进行测试。
举例:
List mock = mock( List.class ); when( mock.get(0) ).thenReturn( 1 ); assertEquals( "预期返回1", 1, mock.get( 0 ) );// mock.get(0) 返回 1
其 中 mock 是模拟 List 的对象,拥有 List 的所有方法和属性。when(xxxx).thenReturn(yyyy); 是指定当执行了这个方法的时候,返回 thenReturn 的值,相当于是对模拟对象的配置过程,为某些条件给定一个预期的返回值。可以理解为对于我们要测试的方法中,有需要调用mock的对象的对应方法,当调用到此方法时,对于返回值的设定。
Assert 说明
junit中的assert方法全部放在Assert类中,下面简单介绍两个:
1.assertTrue/False([String message,]boolean condition);
用来查看变量是是否为false或true,如果assertFalse()查看的变量的值是false则测试成功,如果是true则失败,assertTrue()与之相反;
2.fail([String message,]);
直接用来抛出错误。
3.assertEquals([String message,]Object expected,Object actual);
判断是否相等,可以指定输出错误信息。
第一个参数是期望值,第二个参数是实际的值。
这个方法对各个变量有多种实现
验证Verify
前面提到的 when(……).thenReturn(……) 属于状态测试,某些时候,测试不关心返回结果,而是侧重方法有否被正确的参数调用过,这时候就应该使用 验证方法了。从概念上讲,就是和状态测试所不同的“行为测试”了。
一旦使用 mock() 对模拟对象打桩,意味着 Mockito 会记录着这个模拟对象调用了什么方法,还有调用了多少次。最后由用户决定是否需要进行验证,即 verify() 方法。
mockedList.add("one");
mockedList.add("two");
verify(mockedList).add("one"); // 如果times不传入,则默认是1 verify 内部跟踪了所有的方法调用和参数的调用情况,然后会返回一个结果,说明是否通过。若调用成功,则程序正常运行,反之则会报告:Wanted but not invoked :verify(mockedList).add("one")
Map mock = Mockito.mock( Map.class ); when( mock.get( "city" ) ).thenReturn( "广州" ); // 关注参数有否传入 verify(mock).get( Matchers.eq( "city" ) ); // 关注调用的次数 verify(mock, times( 2 ));
也就是说,这是对历史记录作一种回溯校验的处理。
再来一个例子相信大家就明白了
//首先要importMockito.
import static org.mockito.Mockito.*;
//mock creation
List mockedList = mock(List.class);
//using mock object
mockedList.add("one");
mockedList.clear();
//验证add方法是否在前面被调用了一次,且参数为“one”。clear方法同样。
verify(mockedList).add("one");
verify(mockedList).clear();
//下面的验证会失败。因为没有调用过add("two")。
verify(mockedList).add("two");
以上只是对于单元测试的常用方法做了简单的说明,但是junit4还有很多强大的功能,例如:限时测试,测试异常,参数化测试,以及打包测试等,这些功能也同样很实用,还需要大家慢慢挖掘。
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/hejingyuan6/article/details/49851109