本文为霍格沃兹测试学院优秀学员 Junit 学习笔记。测试开发技能进阶,文末加群。
先看 Wikipedia 上的解释:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0Jm3tXGg-1656582570014)(upload://8jWz3HKy5I2etJ9vjD2dbbEetbj.png)]
xUnit 是一系列测试框架的统称,最开始来源于一个叫做 Smalltalk 的 SUnit 框架,现在各种面向对象的语言,如 Java、Python 的鼻祖就是 Smalltalk,后来这些语言都借助了 Sunit 框架的理念,有很多通用的规范和特征,也就统称为 xUnit。
1)创建 maven 工程 XUnit,pom.xml 中添加 Junit 依赖;
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
2)src/test/java 下创建测试类 Junit4DemoTest
注意
- 测试类要以 Test 开头或者结尾
- maven auto-import
- src/main/java 存放应用实现代码
- src/test/java 存放单元测试
- 单元测试的原则之一:用例可以独立运行
基本测试 demo 运行:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Ubp1GqGk-1656582570015)(upload://zYDXBDKdc06b8PaduzztmAsbEE8.jpeg)]
运行结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1d162j50-1656582570016)(upload://oiiQ0PkfpF9Fc8mGMb8tDOZkHWX.png)]
Junit4:
TestNG、Junit5:
顺序演示
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CBvFO3Yu-1656582570016)(upload://msjUplbkg01rWq37cHhSUzUl0t4.png)]
运行结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-bIF72WSf-1656582570016)(upload://1Abj7o2tq54zCBiTyWzEArJtTCi.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-UpFcTne0-1656582570016)(upload://iaTb7N3vkcqE4i1BYsL5nFpEuBN.png)]
实操演示 1
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-snGUEenv-1656582570017)(upload://q6kbgulKtspFvzyhZKhpzz8xHpU.png)]
运行结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hHnEkwd5-1656582570017)(upload://3Tc15AvkIxjXVSsfGpNDNIsHMEL.png)]
实操演示 2
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-j7rpQfjE-1656582570017)(upload://5ca75hIUQOExWC92GpgCESlhs5X.png)]
运行结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LCu7BzlM-1656582570018)(upload://lzyWt6d5iw4A0MlGwd22kPaF6jY.png)]
流程顺序:
实操演示 1
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-a0RQMTCU-1656582570018)(upload://8frvbr4gvqZ55R13geeHw2UAPpH.png)]
运行结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WD4QzSPj-1656582570018)(upload://jkbT7odg8Orc0XpZGTEAalnyDiR.png)]
从运行结果中我们可以看到,子类会将与父类中一样的方法进行覆盖,只执行子类中的方法
实操演示 2
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A6md8fLw-1656582570018)(upload://kCoxnAJG9V3mgzrRt6yMhBqWFpC.png)]
运行结果:
我是 @BeforeClass,我是第一步
我是 Children@BeforeClass,我是第一步
我是 @Before,用例执行前先到我这
我是 Children@Before,用例执行前先到我这
Children testDemoB
我是 Children@After, 用例执行后到我这
我是 @After, 用例执行后到我这
我是 @Before,用例执行前先到我这
我是 Children@Before,用例执行前先到我这
Children testDemoA
我是 Children@After, 用例执行后到我这
我是 @After, 用例执行后到我这
java.lang.AssertionError
at org.junit.Assert.fail(Assert.java:86)
at org.junit.Assert.assertTrue(Assert.java:41)
at org.junit.Assert.assertTrue(Assert.java:52)
...
at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
我是 @Before,用例执行前先到我这
我是 Children@Before,用例执行前先到我这
Children testDemoC
我是 Children@After, 用例执行后到我这
我是 @After, 用例执行后到我这
我是 @Before,用例执行前先到我这
我是 Children@Before,用例执行前先到我这
testDemoA
我是 Children@After, 用例执行后到我这
我是 @After, 用例执行后到我这
java.lang.AssertionError
at org.junit.Assert.fail(Assert.java:86)
at org.junit.Assert.assertTrue(Assert.java:41)
at org.junit.Assert.assertTrue(Assert.java:52)
...
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
我是 @Before,用例执行前先到我这
我是 Children@Before,用例执行前先到我这
testDemoB
我是 Children@After, 用例执行后到我这
我是 @After, 用例执行后到我这
我是 @Before,用例执行前先到我这
我是 Children@Before,用例执行前先到我这
testDemoC
我是 Children@After, 用例执行后到我这
我是 @After, 用例执行后到我这
我是 Children@AfterClass,我是最后一步
我是 @AfterClass,我是最后一步
实操演示
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-YiG4Synz-1656582570019)(upload://xgCCKtSCs4yhIwNvlm6XD7NHshU.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A8G42KnZ-1656582570019)(upload://z2R0uLXJxd30u6jrZZfIo1YfRkz.png)]
运行结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-spUDPrXE-1656582570019)(upload://ccGp7txjiWN4D7NcCQReXf5CqFT.png)]
我是 @Before,用例执行前先到我这
我是 Children2@Before,用例执行前先到我这
Children2 testDemoC
我是 Children2@After, 用例执行后到我这
我是 @After, 用例执行后到我这
我是 @Before,用例执行前先到我这
我是 Children2@Before,用例执行前先到我这
Children2 testDemoB
我是 Children2@After, 用例执行后到我这
我是 @After, 用例执行后到我这
我是 @Before,用例执行前先到我这
我是 Children2@Before,用例执行前先到我这
Children2 testDemoA
我是 Children2@After, 用例执行后到我这
我是 @After, 用例执行后到我这
java.lang.AssertionError
at org.junit.Assert.fail(Assert.java:86)
at org.junit.Assert.assertTrue(Assert.java:41)
...
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
我是 @Before,用例执行前先到我这
我是 Children2@Before,用例执行前先到我这
testDemoA
我是 Children2@After, 用例执行后到我这
我是 @After, 用例执行后到我这
java.lang.AssertionError
at org.junit.Assert.fail(Assert.java:86)
at org.junit.Assert.assertTrue(Assert.java:41)
...
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
我是 @Before,用例执行前先到我这
我是 Children2@Before,用例执行前先到我这
testDemoB
我是 Children2@After, 用例执行后到我这
我是 @After, 用例执行后到我这
我是 @Before,用例执行前先到我这
我是 Children2@Before,用例执行前先到我这
testDemoC
我是 Children2@After, 用例执行后到我这
我是 @After, 用例执行后到我这
我是 Children2@AfterClass,我是最后一步
我是 @AfterClass,我是最后一步
我是 @BeforeClass,我是第一步
我是 @Before,用例执行前先到我这
testDemoA
我是 @After, 用例执行后到我这
java.lang.AssertionError
at org.junit.Assert.fail(Assert.java:86)
at org.junit.Assert.assertTrue(Assert.java:41)
...
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
我是 @Before,用例执行前先到我这
testDemoB
我是 @After, 用例执行后到我这
我是 @Before,用例执行前先到我这
testDemoC
我是 @After, 用例执行后到我这
我是 @AfterClass,我是最后一步
我是 @BeforeClass,我是第一步
我是 Children@BeforeClass,我是第一步
我是 @Before,用例执行前先到我这
我是 Children@Before,用例执行前先到我这
Children testDemoB
我是 Children@After, 用例执行后到我这
我是 @After, 用例执行后到我这
我是 @Before,用例执行前先到我这
我是 Children@Before,用例执行前先到我这
Children testDemoA
我是 Children@After, 用例执行后到我这
我是 @After, 用例执行后到我这
java.lang.AssertionError
at org.junit.Assert.fail(Assert.java:86)
at org.junit.Assert.assertTrue(Assert.java:41)
at org.junit.Assert.assertTrue(Assert.java:52)
...
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
我是 @Before,用例执行前先到我这
我是 Children@Before,用例执行前先到我这
Children testDemoC
我是 Children@After, 用例执行后到我这
我是 @After, 用例执行后到我这
我是 @Before,用例执行前先到我这
我是 Children@Before,用例执行前先到我这
testDemoA
我是 Children@After, 用例执行后到我这
我是 @After, 用例执行后到我这
java.lang.AssertionError
at org.junit.Assert.fail(Assert.java:86)
at org.junit.Assert.assertTrue(Assert.java:41)
...
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
我是 @Before,用例执行前先到我这
我是 Children@Before,用例执行前先到我这
testDemoB
我是 Children@After, 用例执行后到我这
我是 @After, 用例执行后到我这
我是 @Before,用例执行前先到我这
我是 Children@Before,用例执行前先到我这
testDemoC
我是 Children@After, 用例执行后到我这
我是 @After, 用例执行后到我这
我是 Children@AfterClass,我是最后一步
我是 @AfterClass,我是最后一步
我是 @BeforeClass,我是第一步
我是 Children2@BeforeClass,我是第一步
由测试结果可以看到使用套件后,测试过程为 Junit4DemoChildren2Test、Junit4DemoTest、Junit4DemoChildrenTest 的顺序执行
有时候我们需要对一些特定的用例进行分组测试,这个时候就可以用 @Category
来实现
另外在套件执行类上运用注解:
@RunWith(Categories.class) : 固定写法,指明以 Category 方式分组
@Categories.IncludeCategory(SlowGroup.class) : 指明要执行的测试分组包含哪些
@Categories.ExcludeCategory(FastGroup.class) : 指明要执行的测试分组不包含哪些
@Suite.SuiteClasses({ : 指明要执行的测试类
TestDemo.class
})
@Category
分组需要给定一个标签,以类或者接口都可以,这里创建连个接口 SlowGroup
和 FastGroup
public interface FastGroup {
}
public interface SlowGroup {
}
SlowGroup
、 FastGroup
和 SlowGroup+FastGroup
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0WOYQmtv-1656582570019)(upload://n6QdoTdIy2up4IKNE9sy2FZjoRW.png)]
SlowGroup
组测试执行, FastGroup
组的测试不执行:[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AAmOTSBp-1656582570020)(upload://nfEgokppF4mLaLWRb2DfLisAssg.png)]
测试结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Eh7FCv6z-1656582570020)(upload://n8zCx8ZiHJKTOhEBurkbfCpuA5u.png)]
SlowGroup
组测试执行[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hucJVimv-1656582570021)(upload://wtwTFWEIySVpVyddixqJBFpXVRP.png)]
测试结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-g8ERo2JH-1656582570021)(upload://eTZVx1X1YlSpuHoAHxJhrXcCLc2.png)]
FastGroup
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2gvlVFtF-1656582570021)(upload://tLXtD5E9xT9BD8CDI2q6aPMWqlr.png)]
测试结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-4v1YllWF-1656582570022)(upload://6JAXK4DdP9Liru9WGCSM9ANrhoo.png)]
有时候我们需要传入测试数据,且数据可能是多组,这个时候就需要使用参数化来传入多组数据进行测试
Junit4 的参数化稍微有点麻烦:
1)先在类名上加入注解 @RunWith(Parameterized.class)
表明要以参数化运行
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Stpm5QpX-1656582570022)(upload://84wRy0ZSCyxZ0eVR6ocCFwqXi3M.png)]
2)用注解 @Parameterized.Parameters
来设定数据源
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-7HvcqX8v-1656582570023)(upload://Xk81C3Q6jwrHSE2oO2z4qAqKce.png)]
3)最后用注解 @Parameterized.Parameter 来指定数据源数据对应的参数
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-LSUyLEM5-1656582570023)(upload://tsvQHxvgfEYr6pWFK3jXWnHFL8y.png)]
4)总览
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0ViR1Kul-1656582570023)(upload://Ad9BU8mxzqynk8K84dntITod6re.png)]
测试结果:
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-xjpdcqpI-1656582570024)(upload://z8ccLXiAK5BJQBqsHn450hUQEU8.png)]
从测试结果可以看到 3 组参数分别传入方法中,方法各执行了一次,完成参数化测试
参考文档链接
JUnit4 单元测试框架 [https://junit.org/junit4/]
JUnit5 单元测试框架 [https://junit.org/junit5/]