JUnit4 单元测试入门
Hello World
此文我们通过导入jar包的形式集成Junit4, 下载路径:链接:https://pan.baidu.com/s/1Khi-fMb_k3kfAOluufWcRQ 密码:lz0i。通过eclipse新建一个Java项目后,引入jar包。需要说明的是仅引入junit-4.12是不够的,还需要引入hamcrest-core-1.3,否则会抛出java.lang.NoClassDefFoundError异常。
PS:eclipse中已经集成了JUnit,可以通过Add Library的形式直接引入Junit,方便快捷。
引入jar包后,首先,我们新建一个Hello.class,里面包含一个add(int a, int b)方法用于计算a和b的和。
然后新建一个JUnit test case,和新建普通类一样,右击项目选择新建,进而选择新建一个JUnit test case,如下图所示:
编辑新建的JUnit test case:
public class TestHello {
@Test
public void testAdd() {
assertEquals(2, new HelloWorld().add(1,1));
}
}
直接运行TestHello, 右键TestHello, 选择 Run As –> Junit Test。运行结果如下图所示:
绿色线条代表测试通过,也即是程序运行结果与预期相符:1 + 1 = 2。
常用注解
常用的方法注解
注解名称 | 描述 | 备注 |
---|---|---|
@Test | 声明该方法为测试方法 | |
@BeforeClass | 在测试方法执行前会首先运行该注解所标注的方法,并且只会运行一次,一般用于测试环境的初始化 | public static void |
@AfterClass | 在测试方法执行完毕后会运行该注解所标注的方法,并且只会运行一次,一般用于测试环境的资源释放与清理 | public static void |
@Before | 在每个测试方法执行之前都会首先运行该注解所标注的方法 | public void |
@After | 在每个测试方法执行之后都会运行该注解所标注的方法 | public void |
@Ignore | 被Ignore修饰的方法会被忽略执行 | |
@Test(timeout=毫秒) | 为测试方法指定超时时间 | 单位:毫秒 |
@Test(expected=异常类) | 用于指定期望抛出的异常类型,如果测试方法抛出一个预期的异常则测试通过,否则测试不通过 |
例:
public class TestHello {
@BeforeClass
public static void beforeClass(){
System.out.println("@Before Class");
}
@AfterClass
public static void afterClass(){
System.out.println("@After Class");
}
@Before
public void before(){
System.out.println("@Before");
}
@Test
public void testMethod1() {
System.out.println("@Test");
}
@After
public void after(){
System.out.println("@After");
}
@Test(timeout=1000)
public void testMethod2(){
while(true){
}
}
@Test(expected=NullPointerException.class)
public void testMethod3(){
assertEquals(1, 2);
}
@Ignore
public void ignore(){
System.out.println("@Ignore");
}
}
运行结果:
@Before Class
@Before
@Test
@After
@Before
@After
@Before
@After
@After Class
常用的类注解
注解名称 | 描述 | 备注 |
---|---|---|
@RunWith(xxxx.class) | 用于指定测试类运行器 | 一般使用默认运行器就可以了 |
@SuiteClasses(测试类数组) | 用于组合多个测试类 |
测试用例见下段【JUnit测试套件】
JUnit测试套件
测试套件用于组合多个测试类同时运行。
当测试类很多时,一次只能运行一个测试类无疑是效率低下的。使用测试套件可以一次运行多个测试类,显著提高测试效率。测试套件类形式如下:
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
@SuiteClasses({Test1.class, Test2.class, Test3.class})
public class MainTest {
}
上述测试套件可以一次运行Test1.class, Test2.class, Test3.class三个测试类。测试套件一般为空,其内部代码不会执行。
断言方法
JUnit断言方法主要集成在Assert类中。当断言成功时程序不会执行任何动作,当断言失败时相关信息会被记录下来。
Assert类主要方法有:
方法 | 描述 | 备注 |
---|---|---|
assertArrayEquals(xxxx[] expecteds, xxxx[] actuals) | 断言两个数组内容相同 | 数组元素可以是基本数据类型或者Object对象 |
assertEquals(long expected, long actual) | 断言两个long类型数相等 | |
assertEquals(java.lang.String message, double expected, double actual, double delta) | 断言两个double类型或float类型数相等 | delta指示比较精度,message用于输出提示信息 |
assertFalse(boolean condition) | 断言结果为false | 可以额外输出提示信息 |
assertTrue(boolean condition) | 断言结果为true | 可以额外输出提示信息 |
assertNotNull(java.lang.Object object) | 断言对象非null | 可以额外输出提示信息 |
assertNull(java.lang.Object object) | 断言对象为null | 可以额外输出提示信息 |
assertNotSame(java.lang.Object unexpected, java.lang.Object actual) | 断言不是同一个对象引用 | 可以额外输出提示信息 |
assertSame(java.lang.Object expected, java.lang.Object actual) | 断言同一个对象引用 | 可以输出额外提示信息 |
JUnit参数化设置
当某个方法需要针对多组参数进行测试时该怎么办呢?当然我们可以为每一组参数写一个测试方法,但这无疑是枯燥重复的。我们可以使用JUnit参数化设置来对多组数据进行测试。
使用JUnit参数化设置步凑如下:
1 更改默认测试运行器为 Parameterized.class
2 声明变量来存储预期值和结果值
3 声明一个返回值为Collection的public static 方法,并使用@Parameters进行修饰。
4 为测试类声明一个带有参数的构造方法,并在其中为声明的变量进行赋值。
例:
@RunWith(Parameterized.class)
public class ParameterTest {
int expected = 0;
int input1 = 0;
int input2 = 0;
@Parameters
public static Collection<Object[]> initParameters(){
ArrayList<Object[]> parList = new ArrayList<Object[]>();
parList.add( new Integer[]{3, 1, 2});
parList.add(new Integer[]{5, 3, 2});
return parList;
}
public ParameterTest(int expected, int input1, int input2) {
this.expected = expected;
this.input1 = input1;
this.input2 = input2;
}
@Test
public void testAdd(){
assertEquals(expected, Math.addExact(input1, input2));
}
}
以上代码会首先执行initParameters()方法生成一个参数集合,集合中的每个对象就是一组测试参数。然后执行ParameterTest()构造方法为每一组测试提供一组测试参数,最后执行testAdd()测试方法进行一组测试。initParameters()方法只会执行一次,ParameterTest()和testAdd()执行次数与参数组数相同。
个人认为,使用Junit参数化设置显得有点繁琐,在一个测试方法内声明多个断言显得更为简单。但不知道会不会有其他需要考虑的因素?
好的习惯
- 测试方法名一般采用【test+被测试方法名】的格式来命名。
- 测试类建议置于test目录下,并与被测试类采用相同的包名。
- 不同代码的测试应该相互独立,一个类对应一个测试类,一个函数对应一个测试函数。
参考链接: