单元测试

作为一个Java开发者,你有很多个测试框架可选,这一节我将介绍传统的JUnit和TestNG,如果你没有接触过这些框架,你可以先看看他们的在线文档。

使用JUnit

你将给你之前的ToDo应用的存储类InMemoryToDoRepository.java编写单元测试,为了突出不同框架的相同和不同之处,所有的单元测试都会验证同一个类的功能。接下来你给子项目repository编写测试,放置测试代码的正确位置是在测试的标准布局里,在src/test/java目录下创建一个名叫InMemoryToDoRepositoryTest.java的类,你可以学习测试驱动开发的相关理论,在代码中添加适当的断言语句,下面这段代码用来测试插入功能的正确性。

  1. import com.manning.gia.todo.model.ToDoItem;
  2. import org.junit.Before;
  3. import org.junit.Test;
  4. import java.util.List;
  5. import static org.junit.Assert.*;
  6. public class InMemoryToDoRepositoryTest {
  7. private ToDoRepository inMemoryToDoRepository;
  8. //用这个注解标识的都会在类的所有测试方法之前执行
  9. @Before
  10. public void setUp() {
  11. inMemoryToDoRepository = new InMemoryToDoRepository();
  12. }
  13. //用这个注解的都会作为测试用例
  14. @Test
  15. public void insertToDoItem() {
  16. ToDoItem newToDoItem = new ToDoItem();  
  17. newToDoItem.setName("Write unit tests");
  18. Long newId = inMemoryToDoRepository.insert(newToDoItem);
  19. //错误的断言会导致测试失败 
  20. assertNull(newId);
  21. ToDoItem persistedToDoItem = inMemoryToDoRepository.findById(newId);
  22. assertNotNull(persistedToDoItem);
  23. assertEquals(newToDoItem, persistedToDoItem);
  24. }
  25. }

接下来你需要在依赖配置中添加JUnit的依赖:

  1. project(':repository'){
  2. repositories {
  3. mavenCentral()
  4. }
  5. dependencies {
  6. compile project(':model')
  7. testCompile 'junit:junit:4.11'
  8. }
  9. }

之前我们讲过test任务会先编译源代码,生成Jar文件,然后编译测试代码最后执行测试,下面的命令行输出显示了有一个断言出错的情况:

  1. $ gradle :repository:test
  2. :model:compileJava
  3. :model:processResources UP-TO-DATE
  4. :model:classes
  5. :model:jar
  6. :repository:compileJava
  7. :repository:processResources UP-TO-DATE
  8. :repository:classes
  9. :repository:compileTestJava
  10. :repository:processTestResources UP-TO-DATE
  11. :repository:testClasses
  12. :repository:test
  13. com.manning.gia.todo.repository.InMemoryToDoRepositoryTest
  14. > testInsertToDoItem FAILED//出错方法的名字
  15. java.lang.AssertionError at InMemoryToDoRepositoryTest.java:24
  16. //测试结果概括
  17. 1 test completed, 1 failed
  18. :repository:test FAILED
  19. FAILURE: Build failed with an exception.
  20. * What went wrong:
  21. Execution failed for task ':repository:test'.
  22. > There were failing tests. See the report at:
  23. file:///Users/ben/dev/gradle-in-action/code/chapter07/junit-test-
  24. failing/repository/build/reports/tests/index.html

从输出可以看出一个断言失败了,这正是你想看到的,显示的信息并没有告诉你为什么测试失败了,指示告诉你第24行的断言失败了,如果你有很多个测试,你需要打开测试报告才能找到出错的原因,你可以在任务使用-i选项打印日志输出:

  1. $ gradle :repository:test i
  2. ...
  3. com.manning.gia.todo.repository.InMemoryToDoRepositoryTest
  4. > testInsertToDoItem FAILED
  5. java.lang.AssertionError: expected null, but was:<1>
  6. at org.junit.Assert.fail(Assert.java:88)
  7. at org.junit.Assert.failNotNull(Assert.java:664)
  8. at org.junit.Assert.assertNull(Assert.java:646)
  9. at org.junit.Assert.assertNull(Assert.java:656)
  10. at com.manning.gia.todo.repository.InMemoryToDoRepositoryTest
  11. .testInsertToDoItem(InMemoryToDoRepositoryTest.java:24)
  12. ...

在堆栈树我们可以找到出错的原因是newId的值我们假定是null的实际上为1,所以断言出错了,修改之后再运行可以看到所有测试都通过了:

  1. $ gradle :repository:test
  2. :model:compileJava
  3. :model:processResources UP-TO-DATE
  4. :model:classes
  5. :model:jar
  6. :repository:compileJava
  7. :repository:processResources UP-TO-DATE
  8. :repository:classes
  9. :repository:compileTestJava
  10. :repository:processTestResources UP-TO-DATE
  11. :repository:testClasses
  12. :repository:test

Gradle可以生成更加视觉化的测试报告,你可以在build/reports/test目录下找到HTML文件,打开HTML文件你应该可以看到类似这样的东西:

单元测试 - 图1

使用其他测试框架

你可能在你的项目中想使用其他的测试框架比如TestNG和Spock

使用testNG

比如你想用testNG来编写相同的测试类,相似的,你用testNG指定的注解来标识相应的方法,要想你的构建执行testNG测试,你需要做两件测试:

  1. 声明对testNG库的依赖
  2. 调用Test#useTestNG()方法来声明测试过程使用testNG框架

如下图所示来配置脚本文件:

  1. project(':repository'){
  2. repositories {
  3. mavenCentral()
  4. }
  5.  
  6. dependencies {
  7. compile project(':model')
  8. testCompile 'org.testng:testng:6.8'
  9. }
  10. //设置使用testNG来测试
  11. test.useTestNG()
  12.  
  13. }