JUnit 是一个测试框架,经常被拿来做单元测试。单元测试的粒度一般是方法。
我们看下如何编写单元测试。
如何编写单元测试
build.gradle 的默认内容如下:
plugins {
id 'java'
}
group 'com.example'
version '1.0-SNAPSHOT'
sourceCompatibility = 1.8
repositories {
mavenCentral()
}
dependencies {
testCompile group: 'junit', name: 'junit', version: '4.12'
}
可以看到在 dependencies 中引入了junit依赖:
testCompile group: 'junit', name: 'junit', version: '4.12'
testCompile
声明的依赖,只有在进行测试时才有效。又或者说,只有在src/test
目录下的代码才会感知到 junit 依赖。
在 src/main/java
中创建 Calculate 类,内容如下:
public class Calculate {
public int add(int a, int b) {
return a+b;
}
}
在src/test/java
中创建 CalculateTest 类,内容如下:
import org.junit.Assert;
import org.junit.Test;
public class CalculateTest {
@Test
public void testAdd_01() {
Calculate calculate = new Calculate();
Assert.assertEquals(3, calculate.add(1, 2));
}
@Test
public void testAdd_02() {
Calculate calculate = new Calculate();
Assert.assertEquals(4, calculate.add(1, 2));
}
}
Assert 类中提供了一系列的断言方案,其中最常用的是assertEquals,第一个参数代表期望的值,第二个参数代表计算出的值。若两个值不相等,则抛出错误,认为测试失败。
在 testAdd_01 函数内部,鼠标右击,选择「Run testAdd_01」,会看到测试成功:

在 testAdd_02 函数内部,鼠标右击,选择「Run testAdd_02」,会看到测试失败:

在 testAdd_01 和 testAdd_02 函数外,鼠标右击,选择「Run CalculateTest」,会看到 testAdd_01 和 testAdd_02 都执行了:

几个问题:
Intellij IDEA 是如何支持 JUnit 测试的?
Intellij IDEA 默认集成了 JUnit 插件,所以可以通过右键菜单选项很方便的测试某个类中的单个测试、某个类的所有测试、某个包下的所有测试、以及 src/test
下的所有测试。
可以从 Intellij IDEA 自带的插件系统中找到该插件,如果禁用该插件,相应的右键菜单选项会消失。
如果要执行src/test
目录下的所有测试代码,怎么做?
Intellij IDEA 中右击该目录,选择 Run All Tests
。
如果将 build.gradle 中的 testCompile
改成compile
,那么能在src/main
目录写测试代码吗?
能。
单测隔离
JUnit 的每一个@Test
声明的测试中,会将非static变量或者非单例隔离开。
举个例子:
import org.junit.Test;
class TestBean {
public int num = 1;
}
public class JUnitDemo {
private TestBean testBean = new TestBean();
@Test
public void test01() {
System.out.println("test01");
System.out.println(testBean.num); // 输出1
// 将 num 修改为 10
testBean.num = 10;
System.out.println(testBean.num); // 输出10
}
@Test
public void test02() {
System.out.println("test02");
System.out.println(testBean.num); // 还是输出1,可见没有受到 test01 的影响
// 将 num 修改为 100
testBean.num = 100;
System.out.println(testBean.num); // 输出 100
}
}
运行 JUnitDemo中所有测试,输出如下:
test01
1
10
test02
1
100
test01先运行,会将 testBean.num 修改为 10。然后 test02 运行,但是开始时 testBean.num 的值仍是 1,可见没有受到 test01 的影响。
为什么会出现这种隔离的效果?因为运行 test01 和 test02 时,JUnitDemo 对象不是同一个。也就是 JUnit 为每一次测试生成一个新对象。这个很容易验证:
import org.junit.Test;
public class JUnitDemo {
@Test
public void test01() {
System.out.println(this);
}
@Test
public void test02() {
System.out.println(this);
}
}
运行所有测试,输出:
JUnitDemo@3d82c5f3
JUnitDemo@66cd51c3
输出结果不同,所以两次this也不是同一个。