背景

在一些项目中不可避免地需要写一些单元测试,以此提升开发效率和方便地进行回归测试,是产品上线中非常重要的一部分,然而实际上算法工程师们好像并不在意单元测试~

考虑到目前项目中主要是写 Scala,因此本文记录下 Scala/Java 中的单元测试框架 JUnit;

另一种框架 ScalaTest 是 Scala 原生的单元测试框架,本身与 JUnit 没有太多相似之处,为了与 Java 更兼容因此使用 JUnit 框架。

使用

首先需要添加 maven 依赖,主要考虑 JUnit4;

1
2
3
4
5
6
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>

添加后即可在 test 模块下添加测试单元;

语法

注意:@Test 修饰的方法不能写在 Object 对象中,否则报错。

装饰符

  • @Before

    每个方法都会执行一次,用于初始化信息;

  • @After

    每个方法都会执行一次,在每个测试方法之后执行;

  • @BeforClass

    针对所有测试方法, 只会执行一次且方法必被 static 关键词修饰

  • @AfterClass

    针对所有测试方法, 只会执行一次且方法必被 static 关键词修饰

  • @Test

    装饰测试方法

  • @Test(expected = NullPointerException.class)

    用来指示期望抛出的异常类型。 抛出指定的异常类型,则测试通过; 否则测试失败;

  • @Ignore

    忽略的测试方法

断言

序号方法和描述
1void assertEquals(boolean expected, boolean actual) 检查两个变量或者等式是否平衡
2void assertTrue(boolean expected, boolean actual) 检查条件为真
3void assertFalse(boolean condition) 检查条件为假
4void assertNotNull(Object object) 检查对象不为空
5void assertNull(Object object) 检查对象为空
6void assertSame(boolean condition) assertSame() 方法检查两个相关对象是否指向同一个对象
7void assertNotSame(boolean condition) assertNotSame() 方法检查两个相关对象是否不指向同一个对象
8void assertArrayEquals(expectedArray, resultArray) assertArrayEquals() 方法检查两个数组是否相等

执行顺序

多个测试用例

@BeforeClass -> @Before -> @Test -> @After -> … -> @Before -> @Test -> @After -> @AfterClass

常见问题

  1. java.lang.Exception: Test class should have public zero-argument constructor
    @Test 装饰的测试函数不能写在 object 对象中,否则报出上述异常。

示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
import org.junit.Assert._
import org.junit._

// junit 4
object UsingJUnit {
@BeforeClass
def beforeClass(): Unit = {
println("before class")
}

@AfterClass
def afterClass(): Unit = {
println("after class")
}
}

class UsingJUnit {

@Before
def before(): Unit = {
println("before test")
}

@After
def after(): Unit = {
println("after test")
}

@Test
def testList(): Unit = {
println("testList")
val list = List("a", "b")

assertEquals(List("a", "b"), list)
assertNotEquals(List("b", "a"), list)
}
}

// junit check exception
class JunitCheckException {

val _thrown = rules.ExpectedException.none

@Rule
def thrown = _thrown

@Test(expected = classOf[IndexOutOfBoundsException])
def testStringIndexOutOfBounds(): Unit = {
val s = "test string"
s.charAt(-1)
}

@Test
def testStringIndexOutOfBoundsExceptionMessage(): Unit = {
val s = "test string"
thrown.expect(classOf[IndexOutOfBoundsException])
thrown.expectMessage("String index out of range: -1")
s.charAt(-1)
}
}