Junit4 单元测试

最近公司一直在鼓励写单元测试,故最近自己也整理了些比较常用的单元测试用法,在这里跟大家分享!

以下便是我们经常写的一个测试类,那么其中的一些内容我们是否完全都理解呢,下面我来给大家介绍下:

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的。

二:使用Mockito

介绍:

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");

原文中的一句话很重要:Once created, mock will remember all interactions.所以mockito知道前面是否调用过某方法。

总结:

以上只是对于单元测试的常用方法做了简单的说明,但是junit4还有很多强大的功能,例如:限时测试,测试异常,参数化测试,以及打包测试等,这些功能也同样很实用,还需要大家慢慢挖掘。

附:JUnit4 学习

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-08-05 07:03:50

Junit4 单元测试的相关文章

[转]method initializationerror not found:JUnit4单元测试报错问题

method initializationerror not found:JUnit4单元测试报错问题 原文地址:http://blog.csdn.net/chenleixing/article/details/44257839 2015-03-14  分类: Maven-JUnit-JProfiler等工具(14)  版权声明:本文为博主原创文章,未经博主允许不得转载. 今天使用JUnit 4进行单元测试时,测试程序一直运行不起来,报method initializationerror not

Spring MVC Junit4 单元测试

@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { "/config/spring3/applicationContext.xml" })//启动Spring容器 public class TestISrmVendorService { //注入Spring容器中的Bean @Autowired private ISrmVendorService srmVendorService; @T

Junit4单元测试的基本用法

看了一些Junit4的视频,简单了解了Junit4的一些基本用法,整理记录一下. 环境搭建 这里使用的开发工具是MyEclipse,首先新建一个Java工程,将Junit4的jar包引入,eclipse和MyEclipse都集成了Junit的jar包,详细操作如下图. 1.新增一个Junit的jar包,版本选择Junit4 Junit使用 1.Junit最简单的用法 新建一个类被测试类,里面包含一些测试方法,新建一个测试类 1 package junit.util; 2 /** 3 * 被测试类

Junit4单元测试

一.类的定义: 首先创建一个叫songpeng的项目,在项目下定义jiafa类,进行加法的计算 2.JUnit项目引入 将JUnit单元测试包引入这个项目:在该项目上右击点“Properties“,先选“java Build  Path”,再选“libraries”,右边再点击“Add Library...” 在新弹出的对话框中选中“JUnit”,点Next,在对话框中选Junit4,点“Finish” 3.在Eclipse的Package Explorer中右击该类弹出菜单,选择“JUnit 

Android--socket连接无线模块获取传感器数据------JUnit4单元测试

服务器代码单元测试: package com.qilu.iot;import java.io.BufferedReader;import java.io.IOException;import java.io.InputStream;import java.io.InputStreamReader;import java.net.ServerSocket;import java.net.Socket;import org.junit.Test;import android.app.Activity

method initializationerror not found:JUnit4单元测试报错问题

今天使用JUnit 4进行单元测试时,测试程序一直运行不起来,报method initializationerror not found错误,如下: 网上说版本不对,我试了试,还是有这个问题,后来才知道,缺少了jar包,除了引入junit-4.12.jar之外,还要引入2个依赖jar包:hamcrest-core-1.3.rc2.jar,hamcrest-library-1.3.rc2.jar,提供大家免费的下载链接: junit-4.12.jar下载 hamcrest-library-1.3.

JUnit4单元测试基础篇

引言 JUnit作为Java语言的测试框架,在测试驱动开发(TDD)下扮演重要的角色.众所周知,无论开发大型项目还是一般的小型项目, 单元测试都至关重要.单元测试为软件可发测试维护提供了很大的便利.JUnit 4 作为最新版本,增添了许多新的特性, 结合Hamcrest,可以写出很多灵活的测试.从JUnit 4 开始 jar包放在org.junit包下.代码已经托管在GitHub上. 为了以后测试方便,自定义了一个JUnit的类库,把几个重要的jar包导在一个类库, 这样,以后的项目工程需要写单

Spring-test + Junit4单元测试

一.仅使用Junit进行单元测试不足之处: 1.导致多次Spring容器初始化问题  ->根据JUnit测试方法的调用流程,每执行一个测试方法都会创建一个测试用例的实例并调用setUp()方法.由于一般情况下,我们在setUp()方法中初始化Spring容器,这意味着如果测试用例有多少个测试方法,Spring容器就会被重复初始化多次.虽然初始化Spring容器的速度并不会太慢,但由于可能会在Spring容器初始化时执行加载Hibernate映射文件等耗时的操作,如果每执行一个测试方法都必须重复初

Ecplise中Junit4单元测试的基本用法

看了一些Junit4的视频,简单了解了Junit4的一些基本用法,整理记录一下. 环境搭建 这里使用的开发工具是MyEclipse,首先新建一个Java工程,将Junit4的jar包引入,eclipse和MyEclipse都集成了Junit的jar包,详细操作如下图. 1.新增一个Junit的jar包,版本选择Junit4 Junit使用 1.Junit最简单的用法 新建一个类被测试类,里面包含一些测试方法,新建一个测试类 1 package junit.util; 2 /** 3 * 被测试类