最近公司一直在鼓励写单元测试,故最近自己也整理了些比较常用的单元测试用法,在这里跟大家分享!
以下便是我们经常写的一个测试类,那么其中的一些内容我们是否完全都理解呢,下面我来给大家介绍下:
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不传入,则默认是1verify 内部跟踪了所有的方法调用和参数的调用情况,然后会返回一个结果,说明是否通过。
若调用成功,则程序正常运行,反之则会报告: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