JUnit5依赖注入与测试接口
依赖注入
以前的JUnit的类构造方法和测试方法都是不能有参数的,JUnit Jupiter有一个颠覆性的改进,就是允许它们有入参,这样就能做依赖注入了。
如果你对pytest的fixture有了解的话,就知道这个技术是多么的强大。
ParameterResolver是一个接口类,类构造方法和测试方法在运行时,必须由被注册的ParameterResolver进行解析。JUnit Jupiter有三个自动注册的内置解析器:
- TestInfoParameterResolver 参数类型为TestInfo
- RepetitionInfoParameterResolver 参数类型为RepetitionInfo
- TestReporterParameterResolver 参数类型为TestReporter
TestInfo
TestInfo包含the display name, the test class, the test method, and associated tags等信息。
示例:
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
@DisplayName("TestInfo Demo")
class TestInfoDemo {
TestInfoDemo(TestInfo testInfo) {
assertEquals("TestInfo Demo", testInfo.getDisplayName());
}
@BeforeEach
void init(TestInfo testInfo) {
String displayName = testInfo.getDisplayName();
assertTrue(displayName.equals("TEST 1") || displayName.equals("test2()"));
}
@Test
@DisplayName("TEST 1")
@Tag("my-tag")
void test1(TestInfo testInfo) {
assertEquals("TEST 1", testInfo.getDisplayName());
assertTrue(testInfo.getTags().contains("my-tag"));
}
@Test
void test2() {
}
}
RepetitionInfo
主要是@RepeatedTest会用到,包含当前重复以及总重复次数等信息。
TestReporter
TestReporter能用来输出额外的信息。
示例:
class TestReporterDemo {
@Test
void reportSingleValue(TestReporter testReporter) {
testReporter.publishEntry("a status message");
}
@Test
void reportKeyValuePair(TestReporter testReporter) {
testReporter.publishEntry("a key", "a value");
}
@Test
void reportMultipleKeyValuePairs(TestReporter testReporter) {
Map<String, String> values = new HashMap<>();
values.put("user name", "dk38");
values.put("award year", "1974");
testReporter.publishEntry(values);
}
}
传自定义参数
除了内置解析器,如果想传自定义参数,那么需要使用@ExtendWith注册扩展,比如:
@ExtendWith(RandomParametersExtension.class)
class MyRandomParametersTest {
@Test
void injectsInteger(@Random int i, @Random int j) {
assertNotEquals(i, j);
}
@Test
void injectsDouble(@Random double d) {
assertEquals(0.0, d, 1.0);
}
}
有点插件的意思,更常见的是MockitoExtension和SpringExtension。
测试接口
JUnit Jupiter除了测试类和测试方法,其实也有测试接口,比如:
@TestInstance(Lifecycle.PER_CLASS)
interface TestLifecycleLogger {
static final Logger logger = Logger.getLogger(TestLifecycleLogger.class.getName());
@BeforeAll
default void beforeAllTests() {
logger.info("Before all tests");
}
@AfterAll
default void afterAllTests() {
logger.info("After all tests");
}
@BeforeEach
default void beforeEachTest(TestInfo testInfo) {
logger.info(() -> String.format("About to execute [%s]",
testInfo.getDisplayName()));
}
@AfterEach
default void afterEachTest(TestInfo testInfo) {
logger.info(() -> String.format("Finished executing [%s]",
testInfo.getDisplayName()));
}
}
interface TestInterfaceDynamicTestsDemo {
@TestFactory
default Stream<DynamicTest> dynamicTestsForPalindromes() {
return Stream.of("racecar", "radar", "mom", "dad")
.map(text -> dynamicTest(text, () -> assertTrue(isPalindrome(text))));
}
}
@Test, @RepeatedTest, @ParameterizedTest, @TestFactory, @TestTemplate, @BeforeEach, and @AfterEach能作用到接口的default方法上。
default方法是接口已经实现好了的方法,接口的实现类不需要再编写实现代码,就能直接使用。
如果测试类是@TestInstance(Lifecycle.PER_CLASS)注解,那么可以使用@BeforeAll and @AfterAll。
测试接口可以作为模版。如果测试接口有@ExtendWith and @Tag注解,那么它的实现类也会继承tags and extensions。比如:
@Tag("timed")
@ExtendWith(TimingExtension.class)
interface TimeExecutionLogger {
}
class TestInterfaceDemo implements TestLifecycleLogger,
TimeExecutionLogger, TestInterfaceDynamicTestsDemo {
@Test
void isEqualValue() {
assertEquals(1, "a".length(), "is always equal");
}
}
结果:
INFO example.TestLifecycleLogger - Before all tests
INFO example.TestLifecycleLogger - About to execute [dynamicTestsForPalindromes()]
INFO example.TimingExtension - Method [dynamicTestsForPalindromes] took 19 ms.
INFO example.TestLifecycleLogger - Finished executing [dynamicTestsForPalindromes()]
INFO example.TestLifecycleLogger - About to execute [isEqualValue()]
INFO example.TimingExtension - Method [isEqualValue] took 1 ms.
INFO example.TestLifecycleLogger - Finished executing [isEqualValue()]
INFO example.TestLifecycleLogger - After all tests
测试接口也可以作为契约。比如:
public interface Testable<T> {
T createValue();
}
public interface EqualsContract<T> extends Testable<T> {
T createNotEqualValue();
@Test
default void valueEqualsItself() {
T value = createValue();
assertEquals(value, value);
}
@Test
default void valueDoesNotEqualNull() {
T value = createValue();
assertFalse(value.equals(null));
}
@Test
default void valueDoesNotEqualDifferentValue() {
T value = createValue();
T differentValue = createNotEqualValue();
assertNotEquals(value, differentValue);
assertNotEquals(differentValue, value);
}
}
public interface ComparableContract<T extends Comparable<T>> extends Testable<T> {
T createSmallerValue();
@Test
default void returnsZeroWhenComparedToItself() {
T value = createValue();
assertEquals(0, value.compareTo(value));
}
@Test
default void returnsPositiveNumberWhenComparedToSmallerValue() {
T value = createValue();
T smallerValue = createSmallerValue();
assertTrue(value.compareTo(smallerValue) > 0);
}
@Test
default void returnsNegativeNumberWhenComparedToLargerValue() {
T value = createValue();
T smallerValue = createSmallerValue();
assertTrue(smallerValue.compareTo(value) < 0);
}
}
实现类:
class StringTests implements ComparableContract<String>, EqualsContract<String> {
@Override
public String createValue() {
return "banana";
}
@Override
public String createSmallerValue() {
return "apple"; // 'a' < 'b' in "banana"
}
@Override
public String createNotEqualValue() {
return "cherry";
}
}
小结
本文先介绍了JUnit Jupiter的颠覆性技术,允许传参以实现依赖注入,然后介绍了除了测试类和测试方法以外的测试接口,它既可以作为测试模板,也可以作为测试契约。
参考资料:
https://junit.org/junit5/docs/current/user-guide/#writing-tests-dependency-injection
https://junit.org/junit5/docs/current/user-guide/#writing-tests-test-interfaces-and-default-methods
JUnit5依赖注入与测试接口的更多相关文章
- DDD实战8_2 利用Unity依赖注入,实现接口对应实现类的可配置
1.在Util类库下新建DIService类 /// <summary> /// 创建一个类,对应在配置文件中配置的DIServices里面的对象的 key /// </summar ...
- 在 xunit 测试项目中使用依赖注入
在 xunit 测试项目中使用依赖注入 Intro 之前写过几篇 xunit 依赖注入的文章,今天这篇文章将结合我在 .NET Conf 上的分享,更加系统的分享一下在测试中的应用案例. 之所以想分享 ...
- 再学习之Spring(依赖注入)
一.概述 Spring框架是以 简化Java EE应用程序的开发 为目标而创建的.Spring可以实现很多功能,但是这些功能的底层都依赖于它的两个核心特性,也就是依赖注入和面向切面编程.几乎Sprin ...
- XUnit 依赖注入
XUnit 依赖注入 Intro 现在的开发中越来越看重依赖注入的思想,微软的 Asp.Net Core 框架更是天然集成了依赖注入,那么在单元测试中如何使用依赖注入呢? 本文主要介绍如何通过 XUn ...
- Android 和 Dagger 2 中的依赖注入
原文:Dependency Injection in Android with Dagger 2 作者:Joe Howard 译者:kmyhy 在现代开发团队中到处充斥着"你一定要用依赖注入 ...
- 【10分钟学Spring】:(二)一文搞懂spring依赖注入(DI)
Spring最基础的特性就是创建bean.管理bean之间的依赖关系.下面通过具体实例演示该如何装配我们应用中的bean. Spring提供了三种主要的装配机制 在xml中进行显示的配置 在Java中 ...
- 三大框架 之 Spring(IOC控制反转、DI依赖注入)
目录 常用词汇 left join与left outer join的区别 Struts2的标签库导入 Spring Spring概述 什么是Spring spring特点 下载 IOC 什么IOC 传 ...
- Spring官网阅读(二)(依赖注入及方法注入)
上篇文章我们学习了官网中的1.2,1.3两小节,主要是涉及了容器,以及Spring实例化对象的一些知识.这篇文章我们继续学习Spring官网,主要是针对1.4小节,主要涉及到Spring的依赖注入.虽 ...
- 五:.net core(.NET 6)使用Autofac实现依赖注入
Autofac的简单使用: 由于将来可能引用很多包,为了保持统一队形,我们再新建一个类库项目Wsk.Core.Package,当做包的引用集合: 删掉Class1,把Wsk.Core.Wsk.Core ...
随机推荐
- 密码学系列之:碰撞抵御和碰撞攻击collision attack
密码学系列之:碰撞抵御和碰撞攻击collision attack 简介 hash是密码学和平时的程序中经常会用到的一个功能,如果hash算法设计的不好,会产生hash碰撞,甚至产生碰撞攻击. 今天和大 ...
- NVIDIA GPU上的Tensor线性代数
NVIDIA GPU上的Tensor线性代数 cuTENSOR库是同类中第一个GPU加速的张量线性代数库,提供张量收缩,归约和逐元素运算.cuTENSOR用于加速在深度学习训练和推理,计算机视觉,量子 ...
- CodeGen结构循环回路
CodeGen结构循环回路 structure循环是一个模板文件构造,它允许您迭代CodeGen拥有的有关结构的集合.为了使用结构循环,必须同时基于多个存储库结构生成代码. CodeGen可以通过以下 ...
- NX二次开发-将3X3矩阵修正为正交且长度为单位长度的矩阵
函数:UF_MTX3_ortho_normalize() 函数说明:将矩阵修正为正交且xyz长度为单位长度的矩阵.下图中输入的矩阵为三条线段的端点,经过修正后,生成一个坐标系. 1 #include ...
- C# Net Core 使用 itextsharp.lgplv2.core 把Html转PDF
C# Net Core 使用 itextsharp.lgplv2.core 把Html转PDF 只支持英文(中文我不知道怎么弄,懂的朋友帮我看一下)!!!!![补充:评论区的小伙伴已解决] 引入包it ...
- Java中JVM、JRE和JDK三者有什么区别和联系?
Java 语言的开发运行,也离不开 Java 语言的运行环境 JRE.没有 JRE 的支持,Java 语言便无法运行.当然,如果还想编译 Java 程序,搞搞小开发的话,JRE 是明显不够了,这时候就 ...
- JNI相关笔记 [TOC]
JNI相关笔记 目录 JNI相关笔记 1 生成native code所需要的头文件 2 JNI提供的一些函数和方法 3 局部引用,全局引用,全局弱引用. 4 异常 1 生成native code所需要 ...
- ffmpeg入门到实战-ffmpeg是怎么转码的?
阅读目录 视频是怎么被播放的? ffmpeg命令的格式 ffmpeg转码输出的过程 视频是怎么被播放的? 我们知道,当下大多数播放器都是基于ffmpeg二次开发的.你有没有想过,你用播放器打开一个视频 ...
- npm ERR! Unexpected end of JSON input while parsing near '...'解决方法
npm install时出现npm err! Unexpected end of JSON input while parsing near'...'错误 输入 npm cache clean -- ...
- .net core 支付宝,微信支付 一
源码: https://github.com/aspros-luo/Qwerty.Payment/tree/develop 支付宝支付:参考支付宝sdk及文档,https://docs.open.al ...