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

eclipse junit怎么不进入test代码?_TDD工具集:JUnit、AssertJ和Mockito (十八)编写测试-测试执行顺序\嵌套的测试

2df456e1a46a3ee10f7d03b8e2eb9606.png

cae1103261eab675e7483bc40066aae7.png

85da3f0648016cdd560e8e1e98972585.png

本文分享在编写测试中“测试执行顺序、嵌套的测试”两节内容的方法。

测试执行顺序

重要性:★★★☆☆

如果一个测试类中有多个测试方法,缺省情况下,虽然JUnit会根据一个内在的算法确定这些方法的执行顺序(为了支持“可重复构建”的目标),但是对用户来说,其顺序并不是明显的——测试方法的名称和在测试类中出现的顺序都不是排序的依据。

正常情况下测试类中的每一个测试方法都应该是独立的——它的执行与否以及测试结果都不应该依赖于其他测试方法的预先执行。一个测试方法不应该依赖另一个测试方法为它预设测试条件(例如订单CRUD测试中,查询订单测试不应该依赖于创建订单测试为它先在数据库中创建订单,而应该在自身的setup阶段向数据库中插入测试数据)。

但是有的时候,尤其是在集成测试中,因为要与外部系统如数据库等进行交互,测试类中的每个测试方法在setup阶段都要启动数据库并向其中插入数据,就会导致严重的性能问题。这个时候我们可以接受安排测试方法的执行顺序,例如在订单CRUD测试中,安排创建订单测试先执行,向数据库中插入一到多条订单数据,随后执行查询订单测试和修改订单测试,最后执行删除订单测试。

当需要访问外部基础设施(如数据库、消息中间件等等)或者采用PER_CLASS模式执行测试时,定义测试方法的执行顺序比较有意义。

为了定义测试执行顺序,你需要:

  • @TestMethodOrder注解测试类或测试接口,指定一个MethodOrderer接口的实现类。
  • 如果采用MethodOrdererMethodOrderer.OrderAnnotation类,在每个要排序的测试方法上添加@Order注解。@Order的值越小,方法越先执行。

下面的代码示例根据@Order注解进行排序:

package yang.yu.tdd.exec_order;

import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;

@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
class MethodOrderTest {

    @Test
    @Order(20)
    void last() {
        System.out.println("Me last");
    }

    @Test
    @Order(-6)
    void first() {
        System.out.println("Me first");
    }

    @Test
    @Order(0)
    void second() {
        System.out.println("Me second");
    }

    @Test
    @Order(2)
    void third() {
        System.out.println("Me third");
    }
}

还可以根据方法名称的字母表顺序进行排序:

package yang.yu.tdd.exec_order;

import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;

@TestMethodOrder(MethodOrderer.Alphanumeric.class)
class AlphanumericOrderTest {

    @Test
    void last() {
        System.out.println("Named last but second in fact");
    }

    @Test
    void first() {
        System.out.println("Me first");
    }

    @Test
    void second() {
        System.out.println("Named second but third in fact");
    }

    @Test
    void third() {
        System.out.println("Named third but last in fact");
    }
}

还可以通过将测试类注解为:

@TestMethodOrder(MethodOrderer.Random.class)

来让测试方法伪随机排序执行。不过通常而言这种方式没啥必要。

嵌套的测试

重要性:★★★☆☆

有时候一个测试类中的测试方法太多,有必要根据内聚性原则将它们分组。

可以在测试类的内部定义嵌套内类(不能是静态内类)并注解为@Nested将测试进行分组。在顶层类和嵌套类中都可以定义测试方法和生命周期方法。

嵌套的层级数量没有限制。

如果测试生命周期是PER_METHOD的,嵌套类不允许定义@BeforeAll@AfterAll生命周期方法。如果测试生命周期是PER_CLASS的,嵌套类中可以定义@BeforeAll@AfterAll生命周期方法。

如果外层测试类中有定义@BeforeEach@AfterEach生命周期方法,那么它们也会在嵌套类的每个测试方法前后执行一次。

示例代码如下:

package yang.yu.tdd.nested;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.EmptyStackException;
import java.util.Stack;

import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;

@DisplayName("A stack")
class TestingAStackDemo {

    Stack<Object> stack;

    @Test
    @DisplayName("is instantiated with new Stack()")
    void isInstantiatedWithNew() {
        new Stack<>();
    }

    @Nested
    @DisplayName("when new")
    class WhenNew {

        @BeforeEach
        void createNewStack() {
            stack = new Stack<>();
        }

        @Test
        @DisplayName("is empty")
        void isEmpty() {
            assertTrue(stack.isEmpty());
        }

        @Test
        @DisplayName("throws EmptyStackException when popped")
        void throwsExceptionWhenPopped() {
            assertThrows(EmptyStackException.class, stack::pop);
        }

        @Test
        @DisplayName("throws EmptyStackException when peeked")
        void throwsExceptionWhenPeeked() {
            assertThrows(EmptyStackException.class, stack::peek);
        }

        @Nested
        @DisplayName("after pushing an element")
        class AfterPushing {

            String anElement = "an element";

            @BeforeEach
            void pushAnElement() {
                stack.push(anElement);
            }

            @Test
            @DisplayName("it is no longer empty")
            void isNotEmpty() {
                assertFalse(stack.isEmpty());
            }

            @Test
            @DisplayName("returns the element when popped and is empty")
            void returnElementWhenPopped() {
                assertEquals(anElement, stack.pop());
                assertTrue(stack.isEmpty());
            }

            @Test
            @DisplayName("returns the element when peeked but remains not empty")
            void returnElementWhenPeeked() {
                assertEquals(anElement, stack.peek());
                assertFalse(stack.isEmpty());
            }
        }
    }
}

执行测试结果显示如下,可见输出也是层级化的:

84d417c5a2181cb3eaa547583d92a2c3.png

一种可行的组织测试代码的方式是:为每个被测试的产品类创建一个对应的测试类。在测试类内部,针对被测类的每个工作单元(一般是方法)分别创建一个注解为@Nested的嵌套类,包含针对这个工作单元的所有测试。

这一节就讲到这里,下一节我们讲讲"编写测试中的依赖注入、测试接口以及重复测试"

最后,欢迎你来公众号编程道与术做客,我在那边等你,与你一道交流!

相关文章:

  • win程序 安装 跟踪_Python3.8程序安装就这几步
  • git 设置账号密码_【PyQt5】工具安装和环境设置2//A1.1
  • 视觉在无人驾驶中的应用及分类_机器视觉在自动化焊接中的应用
  • android混淆规则_最佳被虐——Android混淆文件生成器
  • python 图片处理模块_python Pillow 图片处理模块,好强大有没有
  • ubuntu安装python另一个版本_Ubuntu下python两个版本的切换
  • 前端中全部盒子靠左对齐_web前端入门必学的16个知识点,都来看一下吧
  • javaweb不同用户登录不同页面的页面_Javaweb知识点小总结
  • c语言选择排序_C语言必学的12个排序算法:简单选择排序(第6篇)
  • python合并视频和音频_Python实现五毛钱特效
  • gitlab账号密码登录不了_DevOps元素周期表—1号元素 Gitlab
  • python根据输入的三个数求平均分_Python 实现输入任意多个数,并计算其平均值的例子...
  • hive 字符串拼接_Hive行转列详解
  • idea 单元测试_java单元测试覆盖率统计
  • iframe 注入js_基于HTML注入的一种攻击思路
  • [译] React v16.8: 含有Hooks的版本
  • 【腾讯Bugly干货分享】从0到1打造直播 App
  • 4. 路由到控制器 - Laravel从零开始教程
  • Apache的80端口被占用以及访问时报错403
  • ES学习笔记(12)--Symbol
  • Intervention/image 图片处理扩展包的安装和使用
  • JavaScript-Array类型
  • php ci框架整合银盛支付
  • Protobuf3语言指南
  • Redis字符串类型内部编码剖析
  • underscore源码剖析之整体架构
  • use Google search engine
  • v-if和v-for连用出现的问题
  • WebSocket使用
  • Zsh 开发指南(第十四篇 文件读写)
  • 不用申请服务号就可以开发微信支付/支付宝/QQ钱包支付!附:直接可用的代码+demo...
  • 关于使用markdown的方法(引自CSDN教程)
  • 推荐一个React的管理后台框架
  • 小程序上传图片到七牛云(支持多张上传,预览,删除)
  • 新版博客前端前瞻
  • 如何用纯 CSS 创作一个菱形 loader 动画
  • ​ubuntu下安装kvm虚拟机
  • (2)MFC+openGL单文档框架glFrame
  • (Redis使用系列) Springboot 实现Redis消息的订阅与分布 四
  • (新)网络工程师考点串讲与真题详解
  • (一)【Jmeter】JDK及Jmeter的安装部署及简单配置
  • (一)基于IDEA的JAVA基础1
  • (译)计算距离、方位和更多经纬度之间的点
  • (转)mysql使用Navicat 导出和导入数据库
  • (转)为C# Windows服务添加安装程序
  • (转载)(官方)UE4--图像编程----着色器开发
  • .net core 实现redis分片_基于 Redis 的分布式任务调度框架 earth-frost
  • .NET delegate 委托 、 Event 事件,接口回调
  • .NET Framework .NET Core与 .NET 的区别
  • .net MySql
  • .NET 使用 ILRepack 合并多个程序集(替代 ILMerge),避免引入额外的依赖
  • .Net 中的反射(动态创建类型实例) - Part.4(转自http://www.tracefact.net/CLR-and-Framework/Reflection-Part4.aspx)...
  • .NET/C# 在代码中测量代码执行耗时的建议(比较系统性能计数器和系统时间)...
  • .net反编译的九款神器
  • .NET连接MongoDB数据库实例教程