当前位置: 首页 > wzjs >正文

备案号链接工信部网站河南推广网站

备案号链接工信部网站,河南推广网站,关于市场营销的100个问题,蜂蜜做的好网站或案例JUnit5 介绍 什么是 xUnit ? Java 语⾔的 xUnit 主流框架: 什么是 JUnit5 ? JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage JUnit Platform::用于 JVM 上启动测试框架的基础服务,提供命令行,IDE和构建工具等方式执行测试的支持。不仅支持 Junit 自制的测试…

JUnit5 介绍

什么是 xUnit ?

image

Java 语⾔的 xUnit 主流框架:

image

什么是 JUnit5 ?

JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage

  • JUnit Platform::用于 JVM 上启动测试框架的基础服务,提供命令行,IDE和构建工具等方式执行测试的支持。不仅支持 Junit 自制的测试引擎,其他测试引擎也都可以接入。
  • JUnit Jupiter:JUnit Jupiter 提供了 JUnit5 的新的编程模型和扩展模型,是 JUnit5 新特性的核心。内部包含了一个测试引擎,用于在 Junit Platform 上运行。
  • JUnit Vintage:由于 JUint 已经发展多年,为了照顾老的项目,JUnit Vintage 提供了兼容 JUnit4.x、Junit3.x 的测试引擎。

image

通过上述的介绍,不知道有没有发现 JUint5 似乎已经不再满足于安安静静做一个单元测试框架了,它的野心很大,想通过接入不同测试引擎,来支持各类测试框架的使用,成为一个基于 JVM 测试框架的基础平台。因此它也采用了分层的架构,分为了平台层、引擎层、框架层。下图可以很清晰地体现出来:

image

  • 最核心的就是平台层:IDE 和构建工具都是作为客户端和这个平台层交互,以达到在项目中运行测试的目的。TestEngine 的实现在平台层中用于发现和运行测试,并且输出测试报告,并通过平台层返回给客户端。

  • 核心关注点是扩展能力:不仅仅只是存在于测试类级别,在整个测试平台级别,都提供了足够的扩展能力。只需要实现框架本身对 TestEngine 的接口,任何测试框架都可以在 JUnit Platform 上运行,这代表着 JUnit5 将会有着很强的拓展性。只需要一点点工作,通过这一个扩展点,框架就能得到所有 IDE 和构建工具在测试上的支持。这对于新框架来说绝对是好事,在测试和构建这块的门槛更低。如 JUnit Vintage 就是一个 TestEngine 实现,用于执行 JUnit4 的测试。

  • 这些对于一个开发者来说意味着什么呢?这意味着一个测试框架和 JVM 开发市场上所有主流的工具集成的时候,你能更容易地说服你的经理、开发 leader、任何项阻碍你引入这个测试框架的人。

Junit5 新特性

JUnit5 更像是 JUnit4 的一个超集,他提供了非常多的增强:

  • JUnit5 不再是单个库,而是模块化结构的集合。整个 API 分成了:自己的模块、引擎、Launcher、针对 Gradle 和 Surefire 的集成模块。
  • 更强大的断言功能和测试注解。
  • 嵌套测试类:不仅仅是 BDD(Behavior Driven Development)。
  • 动态测试:在运行时生成测试用例。
  • 扩展测试:JUnit5 提供了很多的标准扩展接口,第三方可以直接实现这些接口来提供自定义的行为。通过 @ExtendWith 注解可以声明在测试方法和类的执行中启用相应的扩展。
  • 支持 Hamcrest 匹配和 AssertJ 断言库,可以用它们来代替 JUnit5 的方法。
  • 实现了模块化,让测试执行和测试发现等不同模块解耦,减少依赖。
  • 提供对 Java8 的支持,如 Sream API、Lambda 表达式(允许你通过表达式来代替功能接口)等。
  • 提供了分组断言(允许执行一组断言,且会一起报告)。

迁移指南:

JUnit 平台可以通过 Jupiter 引擎来运行 JUnit 5 测试,通过 Vintage 引擎来运行 JUnit 3 和 JUnit 4 测试。因此,已有的 JUnit 3 和 4 的测试不需要任何修改就可以直接在 JUnit 平台上运行。只需要确保 Vintage 引擎的 jar 包出现在 classpath 中,JUnit 平台会自动发现并使用该引擎来运行 JUnit 3 和 4 测试。

开发人员可以按照自己的项目安排来规划迁移到 JUnit 5 的进度。可以保持已有的 JUnit 3 和 4 的测试用例不变,而新增加的测试用例则使用 JUnit 5。

在进行迁移的时候需要注意如下的变化:

  • 注解在 org.junit.jupiter.api 包中;断言在 org.junit.jupiter.api.Assertions 类中;前置条件在 org.junit.jupiter.api.Assumptions 类中
  • 把 @Before 和 @After 替换成 @BeforeEach 和 @AfterEach
  • 把 @BeforeClass 和 @AfterClass 替换成 @BeforeAll 和 @AfterAll
  • 把 @Ignore 替换成 @Disabled
  • 把 @Category 替换成 @Tag
  • 把 @RunWith、@Rule 和 @ClassRule 替换成 @ExtendWith

Junit5 注解

注解 说明
@Test 表示方法是测试方法(与 JUnit4 的 @Test 不同,它的职责非常单一,不能声明任何属性,拓展的测试将会由 Jupiter 提供额外注解)
@ParameterizedTest 表示方法是参数化测试
@RepeatedTest 表示方法可重复执行
@DisplayName 为测试类或者测试方法设置展示名称
@BeforeEach 表示在每个测试方法之前执行
@AfterEach 表示在每个测试方法之后执行
@BeforeAll 只执行一次,执行时机是在所有测试方法和 @BeforeEach 注解方法之前
@AfterAll 只执行一次,执行时机是在所有测试方法和 @AfterEach 注解方法之后
@Tag 表示单元测试类别。类似于 JUnit4 中的 @Categories
@Disabled 表示测试类或测试方法不执行。类似于 JUnit4 中的 @Ignore
@Timeout 表示测试方法运行如果超过了指定时间将会返回错误
@ExtendWith 为测试类或测试方法提供扩展类引用
  • JUnit5 不再需要手动将测试类与测试方法为 public,包可见的访问级别就足够了。
  • 因为框架会为每个测试类创建一个单独的实例,且在 @BeforeAll/@AfterAll 方法执行时,尚无任何测试实例诞生。因此,这两个方法必须定义为静态方法。

示例:

  • Maven 依赖
        <dependency><groupId>org.junit.jupiter</groupId><artifactId>junit-jupiter</artifactId><version>RELEASE</version><scope>test</scope></dependency>
  • 测试代码
import org.junit.jupiter.api.*;class StandardTests {@BeforeAllstatic void initAll() {System.out.println("BeforeAll");}@BeforeEachvoid init() {System.out.println("BeforeEach");}@Testvoid test1() {System.out.println("test1");}@Testvoid test2() {System.out.println("test2");}@Test@Disabled("for demonstration purposes")void skippedTest() {// not executedSystem.out.println("skippedTest");}@AfterEachvoid tearDown() {System.out.println("AfterEach");}@AfterAllstatic void tearDownAll() {System.out.println("AfterAll");}}

执行结果:

BeforeAll
BeforeEach
test1
AfterEach
BeforeEach
test2
AfterEachfor demonstration purposes
AfterAll

断言

JUnit5 使用了新的断言类:org.junit.jupiter.api.Assertions。相比之前的 Assert 断言类多了许多新的功能,并且大量方法支持 Java8 的 Lambda 表达式。

JUnit5 常用断言方法:

方法 说明
assertEquals(expected, actual) 查看两个对象是否相等。
(类似于字符串比较使用的 equals() 方法)
assertNotEquals(first, second) 查看两个对象是否不相等。
assertNull(object) 查看对象是否为空。
assertNotNull(object) 查看对象是否不为空。
assertSame(expected, actual) 查看两个对象的引用是否相等。
(类似于使用“==”比较两个对象)
assertNotSame(unexpected, actual) 查看两个对象的引用是否不相等。
(类似于使用“!=”比较两个对象)
assertTrue(condition) 查看运行结果是否为 true。
assertFalse(condition) 查看运行结果是否为 false。
assertArrayEquals(expecteds, actuals) 查看两个数组是否相等。
assertThat(actual, matcher) 查看实际值是否满足指定的条件。
fail() 让测试执行失败。

以下为两个与 JUnit4 不太一样的断言方式。

异常断言

JUnit5 提供了一种新的异常断言方式 Assertions.assertThrows(),配合函数式编程就可以进行使用。

我们先来考虑一下下面这个 JUnit4 测试:

@Test(expected = IllegalArgumentException.class)
public void shouldThrowException() throws Exception {Task task = buildTask();LocalDateTime oneHourAgo = LocalDateTime.now().minusHours(1);task.execute(oneHourAgo);
}

想象我们运行这个测试,如果传入到 execute() 方法中的参数是一个过去的时间,会正常抛出一个 IllegalArgumentException 异常。这种情况下,测试会运行通过。

但是如果在 buildTask() 方法中抛出了一个其他类型的异常呢?测试会正常执行,并且会提示你得到的异常和期望异常不匹配。这里问题就出来了,我们只是希望测试是在指定位置得到指定的异常,而不是在整个测试体中出现的异常都作为对比异常。

为此,在 JUnit5 中,提供了一个 assertThrows() 方法,可以非常轻松地处理这个问题:

@Test
void shouldThrowException() throws Exception {Task task = buildTask();LocalDateTime oneHourAgo = LocalDateTime.now().minusHours(1);assertThrows(IllegalArgumentException.class,() -> task.execute(oneHourAgo));
}

超时断言

同样的,Junit5 还提供了 Assertions.assertTimeout() 方法,为测试方法的指定位置,设置超时测试。

在这种情况下,就不会担心测试的 setup 阶段对代码执行时间的影响,你可以指定只去衡量某一段代码的执行时间。

另外还提供了一个选项:当出现超时的时候,是选择停止执行(即断言失败)还是继续当前测试(以衡量代码执行的真实完整时间)。

@Test
void shouldTimeout() throws Exception {ExpensiveService service = setupService();assertTimeout(ofSeconds(3), () -> {service.expensiveMethod();});
}

AssertAll(软断言)

问题现象:有⼀个⽅法存在多个断⾔,但是其中⼀个断⾔失败了,后⾯的断⾔都没有执⾏,难道我要等第⼀个问题修好了才能继续检查后⾯的断⾔么?

问题原因:因为原来使⽤的是 JUnit5 的普通断⾔,当⼀个断⾔失败会直接跳出测试⽅法,导致后⾯的断⾔⽆法执⾏,此时的脚本容错性较低。

解决思路

  • 拆开多个测试⽅法,每个测试⽅法进⾏⼀个断⾔。(会造成⼤量重复代码,此⽅案被否)
  • 使⽤软断⾔,即使⼀个断⾔失败,仍会进⾏进⾏余下的断⾔,然后统⼀输出所有断⾔结果。

实施⽅案:可以使⽤ JUnit5 提供的 Java8lambdas的断⾔⽅法,当⼀个断⾔失败,剩下的断⾔依然会执⾏,脚本的容错性增强。

Junit5 带来新的断⾔⽅式assertAll 断⾔⽅法,会在执⾏完所有断⾔后统⼀输出结果,⼀次性暴露所有问题,提⾼了测试脚本的健壮性。

    @Testpublic void fun() {// 组内有一个断言方法不通过,则整组断言结果也不通过assertAll("断言描述1",() -> assertEquals(1, 2),  // 断言失败() -> System.out.println("测试打印")  // 即使上一行断言失败,仍能执行该行代码);// 若上组断言不通过,则该组断言不执行assertAll("断言描述2",() -> assertEquals(1, 2),() -> assertEquals(2, 2));}

运行结果:

测试打印expected: <1> but was: <2>
Comparison Failure: 
Expected :1
Actual   :2
<Click to see difference>org.opentest4j.MultipleFailuresError: 断言描述1 (1 failure)org.opentest4j.AssertionFailedError: expected: <1> but was: <2>
.....

综合示例

class AssertionsDemo {@Testvoid standardAssertions() {assertEquals(2, 2);assertEquals(4, 4, "The optional assertion message is now the last parameter.");assertTrue(2 == 2, () -> "Assertion messages can be lazily evaluated -- "+ "to avoid constructing complex messages unnecessarily.");}@Testvoid groupedAssertions() {// In a grouped assertion all assertions are executed, and any// failures will be reported together.assertAll("person",() -> assertEquals("John", person.getFirstName()),() -> assertEquals("Doe", person.getLastName()));}@Testvoid dependentAssertions() {// Within a code block, if an assertion fails the// subsequent code in the same block will be skipped.assertAll("properties",() -> {String firstName = person.getFirstName();assertNotNull(firstName);// Executed only if the previous assertion is valid.assertAll("first name",() -> assertTrue(firstName.startsWith("J")),() -> assertTrue(firstName.endsWith("n")));},() -> {// Grouped assertion, so processed independently// of results of first name assertions.String lastName = person.getLastName();assertNotNull(lastName);// Executed only if the previous assertion is valid.assertAll("last name",() -> assertTrue(lastName.startsWith("D")),() -> assertTrue(lastName.endsWith("e")));});}@Testvoid exceptionTesting() {Throwable exception = assertThrows(IllegalArgumentException.class, () -> {throw new IllegalArgumentException("a message");});assertEquals("a message", exception.getMessage());}@Testvoid timeoutNotExceeded() {// The following assertion succeeds.assertTimeout(ofMinutes(2), () -> {// Perform task that takes less than 2 minutes.});}@Testvoid timeoutNotExceededWithResult() {// The following assertion succeeds, and returns the supplied object.String actualResult = assertTimeout(ofMinutes(2), () -> {return "a result";});assertEquals("a result", actualResult);}@Testvoid timeoutNotExceededWithMethod() {// The following assertion invokes a method reference and returns an object.String actualGreeting = assertTimeout(ofMinutes(2), AssertionsDemo::greeting);assertEquals("hello world!", actualGreeting);}@Testvoid timeoutExceeded() {// The following assertion fails with an error message similar to:// execution exceeded timeout of 10 ms by 91 msassertTimeout(ofMillis(10), () -> {// Simulate task that takes more than 10 ms.Thread.sleep(100);});}@Testvoid timeoutExceededWithPreemptiveTermination() {// The following assertion fails with an error message similar to:// execution timed out after 10 msassertTimeoutPreemptively(ofMillis(10), () -> {// Simulate task that takes more than 10 ms.Thread.sleep(100);});}private static String greeting() {return "hello world!";}}

参数化测试

在 JUnit4 中,如果想要实现参数化测试(

http://www.dtcms.com/wzjs/402817.html

相关文章:

  • 乐清网站建设公司网页制作教程步骤
  • 做服装到哪个网站拿货品质好关键词资源
  • 游戏网站建设免费广东又出现新病毒
  • 网站设计师英文最简短的培训心得
  • 西安网站制作公司官网网络优化的基本方法
  • 网站建设的讲话稿百度指数趋势
  • 如何制作外贸网站免费网站模板库
  • 腾讯企点怎么解绑手机号南昌seo推广
  • 做投融资平台的网站都有哪些温州seo博客
  • 龙华建站公司网站站内推广怎么做
  • 品牌手机网站开发公司哪家好营销宣传图片
  • 自媒体平台账号排名seo怎么样
  • 无锡网站建设xinysu网站百度手机端排名怎么查询
  • 网络营销公司经营范围百度seo推广首选帝搜软件
  • 网站建设好多钱seo软件简单易排名稳定
  • 山东华邦建设集团网站app推广策划方案
  • 华强北做电子网站东莞做网站公司
  • 动态网站建设实训心得谷歌官方网站注册
  • 网站需求设计文档智能建站网站模板
  • php网站作业郑州短视频代运营公司
  • 文章类网站源码网站推广软件哪个好
  • 电子商务网站建设教程推广形式
  • 徐州做网站费用哈尔滨网络推广优化
  • 建设美食网站的目的和功能定位亚马逊免费的关键词工具
  • 网站被收录网页设计软件dreamweaver
  • 谁做彩票网站代理小学生摘抄新闻
  • 微网站开发平台系统软件企业培训机构哪家最好
  • 做免费看电影的网站不违法吗二级域名免费分发
  • 网站seo优化要怎么做关键词指数
  • 做垃圾桶的网站竞价推广是什么工作