单元测试

一、概念与意义

1、概念

​ 单元测试就是针对最小的功能单元编写测试代码。Java程序最小的功能单元是方法,因此对Java程序进行单元测试就是针对单个Java方法的测试。

2、意义

​ 使用main方法进行测试有很多缺点,一是一个类中只能有一个main方法,不能把测试代码分离,二是没有打印出测试结果和期望结果,例如,expected:362800,but actual:123456,三是很难编写一组通用的测试代码。因此我们需要一种测试框架,帮助我们编写测试。

二、JUnit

1、用途与意义

​ JUnit是一个开源的Java语言的单元测试框架,使用最广泛。使用JUnit的好处在于,我们可以非常简单地组织测试代码,还可以统计测试的代码覆盖率,即被测试的代码本身有多少经过了测试。

2、使用

以Eclipse为例,当我们已经编写了一个testUserDaoImpl.java`文件后,我们想对其进行测试,需要编写一个对应的testUserDaoImplTest.java文件,以Test为后缀是一个惯例,并分别将其放入srctest目录中。最后,在Project-Properties-Java Build Path-Libraries中添加JUnit 4的库:
在这里插入图片描述

整个项目结构如下:

在这里插入图片描述

我们来看一下``testUserDaoImplTest.java`的内容:

代码中注解包括@BeforeClass(所有测试方法前执行)、@AfterClass(所有测试方法结束后执行)、@Before(测试方法前执行)、@After(测试方法后执行)、@Test(测试方法)。

package test;

import static org.junit.Assert.*;

import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;

import dao.impl.UserDaoImpl;
import entity.User;

public class UserDaoImplTest {
		
	UserDaoImpl udi=new UserDaoImpl();
	@BeforeClass
	public static void setUpBeforeClass() throws Exception {
	}

	@AfterClass
	public static void tearDownAfterClass() throws Exception {
	}

	@Before
	public void setUp() throws Exception {
	}

	@After
	public void tearDown() throws Exception {
	}

	@Test
	public void testLoginUser() {
		
		String userName="bbsn";
		String passWord="02200059";
		User u=udi.loginUser(userName, passWord);
		assertNotNull(u);
	}

}

核心测试方法testUserDaoImplTest()加上了@Test注解,这是JUnit要求的,它会把带有@Test的方法识别为测试方法。在测试方法内部,我们用assertNotNull(u)表示,期望udi.loginUser(userName, passWord)返回非空Assertion还定义了其他断言方法,例如:

  • assertTrue(): 期待结果为true
  • assertFalse(): 期待结果为false
  • assertNotNull(): 期待结果为非null
  • assertArrayEquals(): 期待结果为数组并与期望数组每个元素的值均相等

运行单元测试非常简单。选中``testUserDaoImplTest.java文件,点击Run-Run As-JUnit Test`,Eclipse会自动运行这个JUnit测试,并显示结果:

如果测试结果与预期不符,assertNotNull()会抛出异常,我们就会得到一个测试失败的结果:

在Failure Trace中,JUnit会告诉我们详细的错误结果:

3、断言

我们可以使用断言(Assertion)来测试期望结果,可以方便地组织和运行测试,并查看结果。

(1)assertEquals断言

​ 这是应用非常广泛的一个断言,它的作用是比较实际的值和用户预期的值是否一样,assertEquals在JUnit中有很多不同的实现,以参数expected和actual都为Object类型的为例,assertEquals定义为:

static public void assertEquals(String message, Object expected, Object actual) {
    if (expected== null&& actual == null)
        return;
     if (expected != null&& expected.equals(actual))
        return;
     failNotEquals(message, expected, actual);
 }

​ 其中,expected为用户期望某一时刻对象的值,actual为某一时刻对象实际的值。如果这两值相等的话(通过对象的equals方法比较),说明预期是正确的,也就是说,代码运行是正确的。assertEquals还提供了其它的一些实现,例如整数比较,浮点数的比较等等。

(2)assertTrue与assertFalse断言

​ assertTrue与assertFalse可以判断某个条件是真还是假,如果和预期的值相同则测试成功,否则将失败,assertTrue的定义如下:

staticpublic void assertTrue(String message, boolean condition) {
    if (!condition) 
        fail(message); 
}

​ “condition”表示要测试的状态,如果“condition”的值为false,则测试将会失败。

(3)assertNull与assertNotNull断言

​ assertNull与assertNotNull可以验证所测试的对象是否为空或不为空,如果和预期的相同则测试成功,否则测试失败,assertNull定义为:

staticpublic void assertNull(String message, Objectobject) { 
    assertTrue(message,object == null);
 }

​ 其中,object就是要测试的对对象,如果object为空,该测试成功,否则失败,是不是很简单。

(4)assertSame与assertNotSame断言

​ assertSame和assertEquals不同,assertSame测试预期的值和实际的值是否为同一个参数(即判断是否为相同的引用)。assertNotSame则测试预期的值和实际的值是不为同一个参数。assertSame的定义为:

static publicvoid assertSame(String message, Object expected, Object actual) {
    if (expected== actual) 
        return; 
    failNotSame(message, expected, actual);
 }

​ 而assertEquals则判断两个值是否相等,通过对象的equals方法比较,可以相同引用的对象,也可以不同。

(5)fail断言

​ “fail”断言能使测试立即失败,这种断言通常用于标记某个不应该被到达的分支。例如assertTrue断言中,condition为false时就是正常情况下不应该出现的,所以测试将立即失败,fail的定义为:

staticpublic void fail(String message) {
    throw new AssertionFailedError(message);
 }

​ 当一个失败或者错误出现的时候,当前测试方法的执行流程将会被中止,但是位于同一个测试类中的其他测试将会继续运行。

三、规范

在编写单元测试的时候,我们要遵循一定的规范:

一是单元测试代码本身必须非常简单,能一下看明白,决不能再为测试代码编写测试;

二是每个单元测试应当互相独立,不依赖运行的顺序;

三是测试时不但要覆盖常用测试用例,还要特别注意测试边界条件,例如输入为0null,空字符串""等情况。

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐