文章目录
-
- 一、测试类型
- 二、单元测试
- 三、Junit 简单使用
- 四、常用注解
- 五、在 IntelliJ IDEA 中使用 JUnit 4
一、测试类型
(1)单元测试(Unit test):单元测试注重单一类别. 它们存在的目的是检查这类代码是否按照预期正确运行.
(2)综合测试(Integration test):顾名思义, 集成测试是检查开发的模块和其他模块是否正常工作. 虽然集成测试的代码影响范围比单元测试要广, 但是集成测试和单元测试一样, 也是针对开发者的.
(3)端到端测试(End-to-End test):端到端测试是将整个系统作为一个整体, 然后从用户的角度进行测试. 端到端测试的目的是测试系统在实际使用中是否正常, 因此,通常不需要测试替身(Test Double)
二、单元测试
单元测试的目的: 测试当前代码是否正确, 例如,输入一组数据, 输出预期数据; 输入错误数据, 会出现异常错误等.
在单元测试中, 我们需要确保被测系统是独立的(SUT 没有任何的 DOC), 即当被测系统通过测试时, 所以它可以在任何环境下正常工作.
编制单元测试时, 只需要关注单个类别即可。. 而不需要关注例如数据库服务, Web 服务等组件.
(1)被测系统:被测系统:(System under test, SUT)表示正在测试的系统, 目的是测试系统能否正确操作.根据测试类型的不同, SUT 指代的内容也不同, 例如 SUT 可以是一个类,甚至是一个整个系统.
(2)测试依赖组件(DOC):被测系统所依赖的组件, 例如进程 UserService 单元测试时, UserService 会依赖 UserDao, 因此 UserDao 就是 DOC.
(3)测试替身(Test Double):实际系统依赖多个外部对象, 但在单元测试中, 我们将使用一些功能简单、行为与实际对象相似的假对象 SUT 依赖对象, 为了降低单元测试的复杂性和可实现性. 在这里, 这些假对象被称为 测试替身(Test Double).
测试替身有如下 5 种类型:
- Test stub, 为 SUT 提供数据的假对象. 让我们举一个例子来展示什么 Test stub. 假设我们的模块需要从 HTTP 接口中获取商品价格数据, 获取数据的接口被封装为 getPrice 方法. 测试该模块时, 显然,我们不太可能专门开一个 HTTP 提供此接口的服务器, 相反,提供一个带 getPrice 假对象的方法, 从这个假对象中获取数据. 在这个例子中, 提供数据的假对象就叫做 Test stub.
- Fake object 实现简单功能的假对象. Fake object 和 Test stub 主要区别是 Test stub 侧重于提供数据的假对象, 而 Fake object 没有这个意思. 使用 Fake object 主要原因是某些部件在测试过程中不能使用或运行速度过慢, 因而使用 Fake object 来代替它们.
- Mock object 模拟实际对象, 并且可以验证这一点 Mock object 方法调用是否符合预期. 实际上, Mock object 是 Test stub 或 Fake object 一种, 但是 Mock object 有 Test stub/Fake object 没有特性, Mock object 可灵活配置调用方法产生的行为, 并且可以调用跟踪方法, 例如一个 Mock Object 调用方法时传递了哪些参数? 调用了几次方法等.
- Dummy object: 不用于测试, 但是添加的对象是为了测试代码可以正常编译/运行. 例如,我们调用一个 Test Double 对象的方法, 这种方法需要传几个参数, 但是,无论什么值,一个参数都不会影响测试结果, 那么这个参数就是一个参数 Dummy object. Dummy object 可用于空引, 空对象或常量等等. 简单的说, Dummy object 是那些没用过的, 只是填写参数列表的对象.
- Test Spy 可以包装一个真实的 Java 对象, 并返回包装后的新对象. 若无特殊配置, 调用新对象的所有方法, 都会委派给实际 Java 对象.
mock 和 spy 的区别是: mock 一个完全虚拟的对象是无中生有的, 它的所有方法都是虚拟的;
而 spy 在现有类的基础上包装对象, 也就是说,如果我们不重写 spy 的方法, 所以这些方法的实现实际上是调用包装对象的方法.
单元测试在开发中起着非常重要的作用,它可以发现问题,提高效率java最广泛使用的单元测试框架是Junit,它集成在多个框架或工具中,如IDEA、Spring等。
三、Junit 简单使用
首先,添加依赖:
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <!--限制只能在测试编译时使用--> <scope>test</scope> </dependency>
public class TestJunit {
@Test pulic void testingCrunchifyAddition() {
assertEquals("Here is test for Addition Result: ", 30, addition(27, 3));
}
@Test
public void testingHelloWorld() {
assertEquals("Here is test for Hello World String: ", "Hello + World", helloWorld());
}
public int addition(int x, int y) {
return x + y;
}
public String helloWorld() {
String helloWorld = "Hello +" + " World";
return helloWorld;
}
}
随后使用测试用例:
public class App {
public static void main(String[] args) {
Result result = JUnitCore.runClasses(TestJunit.class);
for (Failure failure : result.getFailures()) {
System.out.println(failure.toString());
}
if (result.wasSuccessful()) {
System.out.println("Both Tests finished successfully...");
}
}
}
四、常用注解
(1)@Test 注解:被@Test 标注的方法就是执行测试用例的测试方法, 例如:
public class TestJunit {
@Test
public void myTest() {
assertEquals("Here is test for Addition Result: ", 30, addition(27, 3));
}
}
方法myTest 被注解@Test 标注, 表示这个方法是一个测试方法, 当运行测试用例时, 会自动调用这个方法
(2)@BeforeClass , @AfterClass, @Before, @After:使用@BeforeClass 和 @AfterClass 两个注解标注的方法会在所有测试方法执行前后各执行一次 使用@Before 和 @After 两个注解标注的方法会在每个测试方法执行前后都执行一次.
(3)TestSuite:如果有多个测试类, 可以合并成一个测试套件进行测试, 运行一个 Test Suite, 那么就会运行在这个 Test Suite 中的所用的测试.
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
@RunWith( Suite.class )
@SuiteClasses( {
JUnitTest1.class, JUnitTest2.class } )
public class AllTests {
}
在这个例子中, 我们定义了一个 Test Suite, 这个 Test Suite 包含了两个测试类: JUnitTest1 和 JUnitTest2, 因此运行 这个 Test Suite 时, 就会自动运行这两个测试类了.
五、在 IntelliJ IDEA 中使用 JUnit 4
如果已经存在test 目录 则可以直接在要测试的类名上,alt+enter 就可以自动生成测试类
然后即可测试
【参考】
【1】https://www.jianshu.com/p/a3fa5d208c93 【2】https://blog.csdn.net/fulishafulisha/article/details/80158392 【3】https://segmentfault.com/a/1190000006731125 【4】https://blog.csdn.net/gentlezuo/article/details/108160864 【5】https://baijiahao.baidu.com/s?id=1647361249282882030&wfr=spider&for=pc