怎么使用Groovy+Spock做单元测试?

2023-11-07

1. 背景  

    平时我们写代码,免不了要进行一些测试,如果没有使用单元测试,对于简单的程序,我们可以写一个main方法,调试查看指定的方法是否符合预期;对于一个服务系统,我们可以使用PostMan等工具来模拟一下真实请求,查看输入输出是否符合预期,这些方法粗暴简单,但是存诸多问题。

  • 很难覆盖所有业务逻辑代码,而且无法统计覆盖率。

  • 无法自动化重复测试,每次都需要人工调用,或者依赖外部工具,效率低下。

  • 如果测试的功能依赖过多其他模块或者依赖外部系统,此时测试难度大。

  • 测试代码和功能代码混合在一起,将带来代码混乱和安全上的问题(如一些测试使用的HTTP后门接口即为不安全)。

    而单元测试正是为解决上述问题而生,对于代码中的大多数Bug,单元测试阶段是最容易被发现的。如果没有进行单元测试,那么后期发现这些Bug的周期会越来越长,修复的成本越来越高。写单元测试确实会占用编码的时间,甚至有些情况下写单元测试的时间会比写业务逻辑代码的时间还要长。但是:

  • 单元测试保证测试的高覆盖率:单元测试是所有测试中最底层的一类测试,是第一个环节,也是最重要的一个环节。

  • 单元测试可以降低软件开发的成本:来自微软的统计数据:bug在单元测试阶段被发现,平均耗时3.25小时,如果漏到系统测试阶段,要花费11.5小时。而且85%的缺陷都在代码设计阶段产生,而发现bug的阶段越靠后,耗费成本就越高,指数级别的增高。

  • 单元测试可以自动化地重复进行测试:这在代码重构时很重要,因为代码重构可能会难免涉及到代码的改动,导致代码逻辑可能和最终需求不一致的问题,但是如果有自动化且可以快速的重复进行测试,并发现问题,将会大大提高重构代码的安全性。

  • 规范代码提升代码质量:想要写出更容易测试的业务代码,需要在满足业务需求的基础上,合理的设计代码结构和规范,换句话说,单元测试促进了代码质量的提高。

Bug在单元测试阶段被发现,平均耗时3.25小时,如果漏到系统测试阶段,要花费11.5小时。

85%的缺陷都在代码设计阶段产生,而发现Bug的阶段越靠后,耗费成本就越高,指数级别的增高。

02  概念和基础 

2.1 测试分类

    功能编码只是软件开发的一小部分工作,为了正确性,测试编码也是必不可少的。下表对单元测试、集成测试和功能测试概念和适用场景简单进行比较。

表1 三种测试类型

测试类型

概念
单元测试

又称模块测试,是针对软件设计的最小单位——程序模块进行正确性检验的测试工作。其目的在于检查每个程序单元能否正确实现详细设计说明中的模块功能、性能、接口和设计约束等要求,发现各模块内部可能存在的各种错误。单元测试需要从程序的内部结构出发设计测试用例,多个模块可以平行地独立进行单元测试。当前被测试的模块外模块都能被mock/stub。

集成测试

在单元测试的基础上,将所有的程序模块进行有序的、递增的测试。集成测试是检验程序单元或部件的接口关系,逐步集成为符合概要设计要求的程序部件或整个系统。

功能测试

假设整个系统是一个黑匣子,从用户界面(或API)开始测试端到端的交互。例如,测试系统自动打开浏览器,通过模拟网页上的按钮点击来选择商品,下单,输入信用卡等动作,并期望在屏幕上“看到”发货订单的跟踪号。

    下图表示了单元测试、集成测试、功能测试之间的关系。

    三类测试关注的方向不同,并且在项目的软件生命周期中需要有不同的调整,下表述了不同测试之间的区别。

表2 不同测试类型的特点(以java栈为例)
单元测试 集成测试 功能试验
试验范围 单个Java类 单个模块或多个类 整个系统
测试重点 正确性Java类 类通信、事务、日志、安全等等 端到端用户体验
结果取决于 Java代码 Java代码、文件系统、网络、数据库、其他系统 Java代码、文件系统、网络、数据库、其他系统,GUI、API端点
稳定性 非常稳定 可能脱离环境变化 非常脆弱(一个微不足道的GUI更改可能会破坏它)
失败的测试意味着 倒退 不是倒退就是环境变化 回归,环境改变,图形用户界面改变
设置所需代价 最小 中等(可能需要外部系统) 高(需要一个正在运行的副本系统)
修复所需的工作量 最小 中等(多个类可能有bug) 中/高(错误可能在应用程序的任何层中)
所需工具 测试框架 测试框架、容器、数据库和外部服务 专门的,有时是专有的外部工具,一个暂存系统
Mock/Stub 需要时使用 很少使用 很少使用
运行单个测试的时间 毫秒 秒或分钟
运行该类型的所有测试的时间 最多5分钟 可能是几个小时 可能是几个小时
测试时机

每次提交后自动

在不同的预定时间间隔自动

发布前自动/手动
涉及人员 研发 研发、测试

研发、架构师、测试、分析师、客户

2.2 测试金子塔

   如右图测试金字塔所示,根据经验,70%的测试应该是纯单元测试,20%是较慢的集成测试,10%是功能测试,本文后续内容限定对单块测试的讨论展开。

03 Groovy & Spock简介 

    当前已经有很多成熟的测试框架,Spock是其中之一。Spock 框架是一个基于Groovy语法的测试框架,而Groovy是基于Java虚拟机的一种敏捷的动态语言,是成熟的面向对象编程语言,既可以用于面向对象编程,又可以用作脚本语言,Groovy给Spock带来了非常大的灵活性,下面对Groovy和Spock加以介绍。

3.1 Groovy

    Groovy具备动态语言(如Python或Ruby)的特性,它没有Java那么多的限制,但同时,它运行在JVM中,又可以利用所有Java库。Groovy语法是Java语法的超集,几乎所有的Java代码(除了一些小的例外)同时是有效的Groovy代码。Groovy开发工具包或GDK(www.Groovy-lang.org/GDK.html)是JDK的增强版,以下为Groovy语言的一些特点:

  • Groovy是一种动态语言(Java是静态的)

  • 是强类型语言(与Java相同)

  • 是面向对象的(与Java相同)

  • 附带GDK(Java有JDK)

  • 在JVM上运行(与Java相同)

  • 支持简洁的代码(与Groovy相比,Java被认为是冗长的)

  • 提供自己的库(例如,web和ORM框架)

  • 可以按原样使用任何现有的Java库(Java也可以调用Groovy代码)

  • 有闭包(Java8有lambda表达式)

  • 支持duck类型(Java有严格的继承)

  • Groovy源代码被编译成Java字节码。

  • 使用Groovy代码中的Java类时,new关键字与Java完全相同。

  • Groovy主要与Java语法兼容。

  • 在Groovy中,类默认是公共的,字段默认是私有的。

  • Groovy自动生成getter和setter。

  • 在Groovy中,分号和return关键字是可选的。

  • Groovy支持可选类型:可以声明变量的类型(如在Java中)或使用def关键字将其留给运行时。

  • Groovy将所有对象都视为true,除非对象是空字符串、空集合、0、null或false。

  • Groovy允许您通过在构造函数中使用字段/值的映射来创建对象。

  • Groovy字符串采用自动模板,类似于JSTL。

  • Groovy附带了大量的实用程序,可以读取XML和JSON文件。

  • Groovy支持闭包,闭包可以用来减少assert语句中的代码行。

  • ObjectGraphBuilder可用于快速创建业务域的树状结构。

  • 可以使用Expando在运行时动态创建Groovy对象。

3.2 Spock

3.2.1 简介

    Spock是基于BDD(Behavior Driven Development行为驱动开发)思想实现的、优秀的测试框架,它可以将枯燥、重复、人工的软件测试工作自动化,功能非常强大。Spock结合Groovy动态语言的特点,提供了各种标签,并采用简单、通用、结构化的描述语言,让编写测试代码更加简洁、高效。

3.2.2 Spock VS. Junit

   Spock是Java:JUnit测试框架(http://junit.org/)的超集,Spock还为通常需要额外库的特性提供了内置功能。Spock的核心是一个能够处理软件应用程序整个生命周期的测试框架,右图表示了几个主要的测试框架之间的关系。

    下表对Spock和Junit这两个场景的测试框架着重进行比较,对各自的特点、优缺点进行阐述。

表3 Spock和Junit对比

Spock

Junit

特点

优点

  • 命名:测试名字可以是一个句子,(中文句子也是OK的)

  • 编写测试用例高效、可读性强

  • 占用工时少、维护成本低

Spock可以做JUnit所做所有事情,还可以做Junit不能够做的事情,所以比较起来无突出优点。

缺点

/
  • 命名:JUnit 的测试名称是 Java 的方法名,而 Java 的方法名又不能在其中插入空格。

  • JUnit本身不支持mock和stubing

  • 如果其中某一次分支测试Case出错了,它的报错信息也不够详尽。

总结

1. Spock采用了一种整体的方法,提供了JUnit功能的超集,同时重用了它与工具和开发环境的成熟集成,保持测试运行程序的向后兼容性。

2. Spock是用Groovy编写的,它没有Java那么冗长。Spock测试比各自的JUnit测试更简洁。更少的代码更易于阅读、调试和长期维护。

3.3 Spock设计思想

3.3.1 基于行为的测试

    为了更好了解Spock的使用,我们首先通过一个具体的业务场景走进Spock.

待测试系统

场景

    假设我们要对一个“消防系统”进行测试:处理单元连接到多个火灾传感器,并连续轮询它们以获取异常读数。发现火灾时,警报声响起。如果火势开始蔓延并且触发了另一个检测器,则会自动呼叫消防队。

(1)如果所有传感器均报告无异常,则表明系统正常,无需采取任何措施。

(2)如果触发了一个传感器,则会发出警报声。

(3)如果触发了多个传感器,则会呼叫消防队。

    面对这个“消防系统”的测试需求,我们使用Spock来描述测试场景,对测试问题进行抽象描述。

待测试代码

测试代码

    以上,Spock通过提供规范性的描述,定义多种标签givenwhenthenwhere等),去描述代码“应该做什么”,“输入条件是什么”,“输出是否符合预期”,从语义层面规范了代码的编写。

3.3.2 使用多个输入集测试

    在实际生产中,我们不可避免需要面对更加复杂的系统。下面我们引入一个场景:假设我们正在测试的应用程序是一个核反应堆的监控系统,它的功能类似于上面所说的消防系统,但有更多的输入传感器,系统如下图所示,系统的组成如下:

  • 多个火灾传感器(输入)

  • 三个辐射传感器处于临界点(输入)

  • 当前压力(输入)

  • 报警(输出)

  • 疏散命令(输出)

  • 通知操作人员反应堆应该关闭(输出)

待测试系统

场景

该系统已经按照核反应堆所需的所有安全要求实施,它定期读取传感器数据,并根据读数发出警报或建议采取纠正措施。以下是一些要求:

(1)如果压力超过150 bars,警报就会响起。

(2)如果触发两个或多个火灾警报,警报响起,并通知操作员需要停机(作为预防措施)。

(3)如果检测到辐射泄漏(来自任何传感器的辐射超过100rads),警报响起,宣布反应堆应在下一分钟内撤离,并向操作人员发送需要关闭的通知。

    通过核反应堆的技术专家咨询,确定至少要检查12个测试场景,如下表所示。

表4 核反应堆需要测试的情景
样本输入 预期产出
电流压力 火灾传感器 辐射传感器 声音报警器 需要关机 x分钟内撤离
150 0 0, 0, 0
150 1 0, 0, 0 是的
150 3 0, 0, 0 是的 是的
150 0 110.4,0.3, 0.0 是的 是的 1分钟
150 0 45.3,10.3, 47.7
155 0 0, 0, 0 是的
170 0 0, 0, 0 是的 是的 3分钟
180 0 110.4,0.3, 0.0 是的 是的 1分钟
500 0 110.4,300, 0.0 是的 是的 1分钟
30 0 110.4,1000, 0.0 是的 是的 1分钟
155 4 0, 0, 0 是的 是的
170 1 45.3、10.f、47.7 是的 是的 3分钟

    表中列出的场景是参数化测试的典型示例:测试逻辑总是相同的(接受这三个输入,期望这三个输出),测试代码只需要为这个单一的测试逻辑处理不同的变量集。本例中,我们有12个场景和6个变量。面对这个场景,最直接方法是编写12个单独的测试。那么问题来了:测试代码重复,而且因为未来的维护困难。如果在系统中添加了一个新变量(例如,一个新的传感器),则必须同时更改所有12个测试。因此需要更好的方法,最好是将测试代码(应该编写一次)与测试数据集和预期输出(应该为所有场景编写)分离。这种测试需要一个明确支持参数化测试的框架。Spock内置了对参数化测试的支持,它有一个友好的DSL语法,专门用于处理多个输入和输出。同样,我们使用Spock来描述测试场景,对测试问题进行抽象。

    

3.3.3 隔离被测试对象

    在处理复杂系统的测试的时候,除了需要面对系统的多输入问题,我们还需要面临被测试系统依赖复杂的问题,我们对一个系统进行测试的时候,所依赖的系统可能还在设计和实现中,或者我们没有操作所依赖系统的权限。

待测试系统

场景

左图以核反应堆监控系统的一部分系统为例:

(1)假设我们正在对一个温度监控器进行测试,被测系统温度监测器不直接与温度传感器通信,它从另一个Java系统温度读取器(由不同的软件公司实现)获取读数。

(2)对温度监视器的要求表明,如果温度读数(上升或下降)的差值大于20度,则应发出警报。

    在现实世界中,系统很少能够轻松构建预期的输入输出,因此我们需要进行将待测试的模块从复杂的系统中隔离出来,对外部依赖的输入输出进行伪造。下面分别介绍Stub和Mock两种方式。

Stub方式对输入进行伪造:

待测试代码

测试代码

Stub对输入进行伪造

 

    和输入进行伪对应,对输出进行伪造也是一项重要的测试技术。

待测试系统

场景

如右图,反应堆的温度控制是系统核心任务,是完全自动化。 

(1)如果温差超过50度,就会自动关闭反应堆。

(2)如果温度差异超过20度,警报仍然会响起,但在这种情况下,反应堆不会关闭,从而允许其他系统采取纠正措施。

(3)关闭反应堆和拉响警报是通过一个外部Java库(我们无法控制它)完成的,该库是作为一个简单的API提供的,被测试系统现在也注入了这个外部API。

Mock方式对输入进行伪造:

待测试代码

测试代码

Mock对输出进行伪造

04 Spock测试  

    上文主要是对一些测试概念和思想进行介绍,下面开始进行一些实践,通过一些小case加深对Spock框架的理解,体会其便利和高效。

4.1 Spock使用入门

4.1.1 环境、配置

        Spock是Java栈的一个测试框架,在Java项目配置Spock只需要在pom文件中引入以下文件,开箱即用,无需复杂操作。

		<!-- Spring boot 自己的测试模块依赖-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<!-- 使用 Spock 必须的依赖:spock 的核心依赖-->
		<dependency>
			<groupId>org.spockframework</groupId>
			<artifactId>spock-core</artifactId>
			<version>1.2-groovy-2.4</version>
			<scope>test</scope>
		</dependency>
		<!-- 使用 Spock 必须的依赖:groovy 库-->
		<dependency>
			<groupId>org.codehaus.groovy</groupId>
			<artifactId>groovy-all</artifactId>
			<version>2.4.15</version>
		</dependency>
		<!-- spock 与 spring 环境的集成 -->
		<dependency>
			<groupId>org.spockframework</groupId>
			<artifactId>spock-spring</artifactId>
			<version>1.2-groovy-2.4</version>
			<scope>test</scope>
		</dependency>

4.1.2 Hello World

    下面就一个整型的加法器进行测试,展示Spock测试基本语法,测试类继承 Specification,并分为given,when,then三个部分,在given部分我们确定条件,在when部分进行调用,在then部分进行判断。

待测试代码

测试代码

4.1.3 Spock代码块

Spock block

描述

given:

输入条件(前置参数)

setup:

用于定义变量、准备测试数据、构建mock对象等;

when:

在这个块中调用要测试的方法;

then:

一般跟在when后使用,尽可以包含断言语句、异常检查语句等等,用于检查要测试的方法执行后结果是否符合预期;

and:

衔接上个标签,补充的作用。

expect:

一般跟在setup块后使用,包含一些assert语句,检查在setup块中准备好的测试环境

where:

预期结果

cleanup:

清除

4.1.4 模拟/伪造

    单元测试的含义在于测试一个单元,测试仅限于某个方法内部的代码。如果这写代码中依赖了外部的服务,或者其他人还未写好的接口,我们不能保证外部服务的可用性,也同样不能等另一个人写好接口后再测试,因此需要通过模拟被调用的外部对象的行为和数据,从而保证单元测试的顺利进行。

    在3.3.3节介绍了Stub和Mock的使用场景,下表对二者进行总结和对比。

分类

详情

Stub

提供测试的条件

Mock

模拟测试的结果

注:事实以上二者很容易混淆

4.1.5 静态方法测试

        Spock扩展第三方PowerMock对静态方法进行测试。Spock的单元测试代码继承自Specification基类,而Specification又是基于JUnit的注解@RunWith()实现的,PowerMock的PowerMockRunner也是继承自JUnit,所以使用PowerMock @PowerMockRunnerDelegate()注解,可以指定Spock的父类Sputnik去代理运行PowerMock,这样就可以在Spock里使用PowerMock去模拟静态方法、final方法、私有方法等。其实Spock自带的GroovyMock可以对Groovy文件的静态方法Mock,但对Java代码支持不完整,只能Mock当前Java类的静态方法。

待测试代码

测试代码

 

 

4.1.6 Spock对集成测试的支持

    Spock除了能够做单元测试,对集成测试也有很好的支持。如我们在测试的时候需要同数据库或者外界系统(接口、mq等)进行交互,Spock也能够胜任这些测试工作,下表展示基于Spock对数据库操作的测试。

Spring context Groovy SQL

4.2 Spock进阶

4.2.1 测试代码可读性

    Spock测试本身可以 self-documenting. 测试的名字可以使用句子命名(支持中文),因此我们在测试函数命名的时候即可以描述清楚测试的需求。

4.2.2 参数化测试

    测试方法检查多个场景,其中测试逻辑总是相同的,并且每次只有输入和输出变量更改。测试代码是固定的,而测试输入和输出数据以参数的形式出现。所有参数共享测试代码。不是为每个场景复制这个公共代码,而是将它集中在一个测试方法上。下图所示为一个加法器的参数化测试案例。

  • 使用Where块

def "测试加法工具"(){
    given: "加法"
    Adder adder = new Adder()
    expect: "计算两数之和判断是否相等"
    adder.add(first, second) == sum
    where: "以下 "
    first    | second    || sum
    1        | 1         || 2
    3        | 2         || 5
}
  • 使用数据管道计算输入/输出参数 

def "测试加法工具"(){
    given: "加法"
    Adder adder = new Adder()
    expect: "计算两数之和判断是否相等"
    adder.add(first, second) == sum
    where: "以下 "
    first        <<        [1, 2, 3]    
    second       <<        [4, 5, 6]
    sum          <<        [5, 7, 9]
}
  • 使用数据生成器:可以编写java程序,批量产生数据:如生成随机数,读取Excel文件等构造测试参数。

  • 使用第三方数据生成器:如https://github.com/Bijnagte/spock-genesis

4.3 Spock规范

    我们在实际编写单元测试的时候,为了保证测试的有效性,是需要通过一些测试规范来对测试过程进行约束。在生产过程中我们不能够为了写单测而写单测,如果忘掉“测试有效性”的初衷,写再多的单元测试,盲目刷高覆盖率的同时必将丧失单元测试的意义。下表展示了一些单元测试的规范,当然也是使用Spock进行单元测试需要遵循的规范。

表 Spock单元测试规范

序号

规范

详情

1

不要为了覆盖率而做单元测试

单元测试不仅仅是为了达到覆盖率统计,更重要的是验证业务代码的正确性、健壮性、逻辑的严谨性以及设计的合理性。

2

不要总想着“补”测试

测试代码并不比普通代码地位低,选择事后补测试,将牺牲掉用测试来驱动代码设计的机会。在编写代码时同步编写单元测试,才能更好的发挥出单元测试的能力。

3

注重测试有效性

执行void方法的时候因为没有返回值,偷懒的做法使用 1==1, 等无效单测

(1)一般来说无返回值的方法,内部逻辑会修改入参的属性值,比如参数是个对象,那代码里可能会修改它的属性值,虽然没有返回,但还是可以通过校验入参的属性来测试 void 方法。

(2)还有一种更有效的测试方式,就是验证方法内部逻辑和流程是否符合预期,比如:

   a. 应该走到哪个分支逻辑?

   b. 是否执行了这一行代码?

   c. for 循环中的代码执行了几次?

   d. 变量在方法内部的变化情况?

4 注重代码可测试性 一条真理:难测试的代码就是烂代码
5 尽量不要跨层测试

如果当前被测方法依赖了其他层或module的逻辑,最好mock掉,尽量不要跨层测试,这属于功能测试或集成测试的范畴。

6

注重测试代码结构 Java单测和用Spock写的单测代码独立编写,Spock单测文件建议名使用*Spec命名。测试代码文件目录结构尽量同被测试代码保持一致。

7

遵守 BCDE 原则

(1)B:Border,边界值测试,包括循环、 特殊取,边界值测试包括循环、 特殊取特殊时间点、数据顺序等。

(2)C:Correct,正确的输入,并得到预期结果。,正确的输入并得到预期结果。

(3) D:Design,与设计文档相结合,来编写单元测试。,与设计文档相结合来编写单元测试。

(4) E:Error,强制错误信息输入(如:非法数据、异常流程业务允许等),并得 ,强制错误信息输入(如:非法数据、异常流程业务允许等),并得到预期结果。

8

确保100%运行成功 不应该忽略单元测试失败的用例,尤其历史版本的单元测试报错时,极有可能是当前变更破坏了原始逻辑,当然不排除原测试代码不够健壮。总的来说一旦报错,一定要求根问底进行定位并解决!

9

不推荐在线上环境执行单元测试 在线上环境package的时候应该通过配置命令跳过单元测试。

10

谨记单元测试存在局限性 单元测试永远无法完全证明代码的正确性!

4.4 生产环境使用Spock

4.4.1 覆盖率

    Jacoco是统计单元测试覆盖率的一种工具,当然Spock也自带了覆盖率统计的功能,这里使用第三方Jacoco的原因主要是国内公司使用的比较多一些。使用Jacoco只需要在pom文件里引用Jacoco的插件:jacoco-maven-plugin,然后执行mvn package 命令即可,执行成功后会在target目录下生成单元测试覆盖率的报告,点开报告找到对应的被测试类查看覆盖情况。配置文件见:https://github.com/damaohongtu/dag-demo/blob/main/dag-backend/pom.xml,效果如下。

项目 详情
配置

步骤1:在pom中引入jacoco插件

步骤2:执行mvn test

单测报告

以上,新增的单侧覆盖率为10%.

覆盖率详情

以上,可以查看单个文件的覆盖情况。

4.4.2 研发流程规范

    在团队共同开发时,我们除了通过默认约定控制单元测试的落地外,更有效的方式是将单元测试融入到测试流程中,限制单元测试是不可或缺的环节,在研发流程进行卡点。Jekins是基于一个基于Java开发的一种持续集成工具,我们可以通过Jenkins流水线来编排我们的发布流程,如下图,我们将单元测试作为研发流程中的一个stage.

4.4.3 Spock单测实战

    下面的视频是一个Jenkins+Jacoco展示Spock单元测试覆盖率的教程。项目https://github.com/damaohongtu/dag-demo/tree/main/dag-backend 中提供了单测编写的示例,持续更新中,若对你有帮助烦请star. 

Jenkins+Jacoco展示Spock单元测试覆盖率

05 总结 

    单元测试无疑能够提高代码质量,间接能够提高开发效率。Spock为单元测试带来了诸多便利,且接入成本极低,在Java栈项目中已经被广泛使用。在生产环境中,团队除了通过默认约定推行单元测试落地,还可以通过水线卡点的方式强制约束,保证新增代码均被单元测试覆盖。在做单元时候,研发人员应该保持“为什么做单测的初心”,坚守单元测试的规范,如果仅仅追求单测覆盖率,那么单元测试本身将毫无意义

06 参考资料 

[1] Groovy语言官网:http://www.groovy-lang.org/

[2] Spock官网:https://spockframework.org/

[3] Spock案例:https://github.com/spockframework/spock-example

[4] Jacoco插件:https://mvnrepository.com/artifact/org.jacoco/jacoco-maven-plugin

[5] Jenkins官网:https://www.jenkins.io/ 

[6] Kapelonis, K. . (2016). Java Testing with Spock. Manning Publications Co.

[7] 奥西洛夫金迎. (2014). 单元测试的艺术 : The art of unit testing: with examples in C#. 人民邮电出版社.

  封面故事 :2022年国庆,湖北巴东茶店子。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

怎么使用Groovy+Spock做单元测试? 的相关文章

  • JS对象其中两个Math对象和日期对象

    JavaScript对象 一 Math对象 1 Math对象的使用 Math对象用来对数字进行与数字相关的计算 该对象 不是构造函数 不需要实例化对象 可以直接使用其静态属性和静态方法 Math对象的常用属性和方法 成员 作用 PI 获取圆

随机推荐

  • Geant4程序的一点技巧总结 2

    4 关于获得粒子状态 获得粒子的总能量 G4Track pTrack pStep gt GetTrack const G4DynamicParticle pParticle pTrack gt GetDynamicParticle pPar
  • 7.设备驱动开发的基本函数

    7 1 I O口函数 无论驱动程序多么复杂 归根结底 无非还是向某个端口或者某个寄存器位赋值 这个值只能是0或1 接收值的就是I O口 与中断和内存不同 使用一个没有 申请的I O端口不会使处理器产生异常 也就不会导致诸如 segmenta
  • Qt4.8升级Qt5.9版本问题总结

    最好先在 pro文件中加上 greaterThan QT MAJOR VERSION 4 QT widgets建议最好和源码对比看着升级 有些问题不看源码 报出来的问题会误导我们 1 106 error class QString has
  • 【pyq文案】可可爱爱、脑回路清奇の朋友圈文案

    1 人每一个身体器官都是无价之宝 全部加起来1个月3000 2 别人出门 辣妹风 复古风 学院风 我出门 打工的勤劳小蜜蜂 3 看见自己就烦 50出 和今天星期四没关系 4 上学时拿钱混日子 上班后拿日子混钱 一辈子都在混 真有我的 5 上
  • 金融时间序列分析:5. AR模型实例(Python)

    0 目录 金融时间序列分析 9 ARMA自回归移动平均模型 金融时间序列分析 8 MA模型实例 Python 金融时间序列分析 7 MA滑动平均模型 金融时间序列分析 6 AR模型实例 金融时间序列分析 5 AR模型实例 Python 金融
  • C++基本设计模式01

    C 基本设计模式01 1 简单工厂模式 不直接在客户端创建类对象 利用工厂类的方法CreateObject来创建 优点 1 客户端和具体类解耦 即分开来 2 不需要担心对象创建的复杂程度 缺点 1 增加新功能通过改变源代码 不符合开闭原则
  • TCP协议详细总结

    计网分层结构 考虑最简单的情况 两台主机之间的通信 这个时候只需要一条网线把两者连起来 规定好彼此的硬件接口 如都用USB 电压10v 频率2 4GHz等 这一层就是物理层 这些规定就是物理层协议 我们当然不满足于只有两台电脑连接 因此我们
  • 数字化转型的五项关键驱动力

    在人工智能进入各个行业领域掀起涟漪的时代 企业更需要积极变革 每年几次的Forrester数字化转型高峰论坛会将全球数字高管和Forrester分析师汇聚一堂 一起探讨数字化演进的现状 我很有幸被邀请作为嘉宾 参与了五月初在芝加哥举行的活动
  • PSO最佳适应度收敛曲线

    第一层模型 确定每项作业的运输路线 和运输线路上每个节点的代理人和运输方式 每项作业根据时间 始终点约束构建节点 运输方式虚拟网络图 根据最短路径原则形成运输路线和运输方式选择的初始方案 PSO 根据节点间价格折扣不同和代理人运输能力不同进
  • Python中经常会出现ModuleNotFoundError错误,这是导入模块时未正确安装或路径错误所致

    Python中经常会出现ModuleNotFoundError错误 这是导入模块时未正确安装或路径错误所致 这个错误的解决方案有很多种 本篇文章将为大家提供一种解决 No module named torch six 错误的方法 当你运行P
  • 全栈必知系列之网络安全篇

    网络安全对前端童鞋来说大多数时候都是听其有之 闻之则无 毕竟在现如今前端如火如荼的时代 大多数东西日益成熟 开箱即用 云服务 框架等已经帮我们做了安全方面的防范 不需要我们去太过于关心前端网络安全 作为一个前端爱好者 最近温习一下这部分知识
  • python之base64编码解码

    Python 2 7 16 default Dec 13 2019 18 00 32 GCC 4 2 1 Compatible Apple LLVM 11 0 0 clang 1100 0 32 4 macos10 15 objc s on
  • 排序算法时间复杂度、空间复杂度、稳定性比较

    排序算法分类 排序大的分类可以分为两种 内排序和外排序 放在内存的称为内排序 需要使用外存的称为外排序 排序算法的时间复杂度和空间复杂度 排序算法 平均时间复杂度 最坏时间复杂度 最好时间复杂度 空间复杂度 稳定性 冒泡排序 O n O n
  • python斐波那契数列前20项_Python每日一练之实现斐波那契数列

    概述 今天主要分享下怎么用Python实现斐波那契数列 大家有空可以玩一下 需求 用Python脚本实现斐波那契数列 思路 斐波那契数列 也称兔子数列 是指1 1 2 3 5 8 13 21 34 55 89 144 这样一个数列 在这个数
  • matlab求长径比,基于数值模拟的气膜孔冷却效率经验公式的修正

    1 引言 燃气轮机叶片冷却的基本方式主要分为内部冷却与外部冷却 而外部冷却中气膜冷却具有明显优势和较强应用前景 是一种广泛采用的冷却技术 气膜冷却的原理如图1所示 通过在高温部件表面开设槽或者小孔 使冷却气体以射流的方式注入到主流高温燃气中
  • 如何使用ChatGPT写论文?

    使用ChatGPT写论文详细操作步骤 说明 ChatGPT是一款ai产品 尽管它非常强大 对我们来说本质上也仅仅是一个辅助工具 切勿让AI完全取代我们的思考能力 目前的ChatGPT写论文还不能一步到位 只能通过一些技巧来完成整篇论文 使用
  • 10个python入门小游戏,零基础打通关,就能掌握编程基础

    不会python就不能用python开发入门级的小游戏 当然不是 我收集了十个python入门小游戏的源码和教程 并且即使你没有python基础 只要跟着这十个小游戏的开发详细教程去做 以及有了全部的源码 那就能自己开发出这样十个pytho
  • andriod build system

    1 入口 build core main mk 2 build core base rules mk 3 AndriodProducts mk 在原生的bulid system里面会 吧所有的改名字的 makefile都 inlucde进去
  • 云服务器被攻击了,怎么处理比较合适,你的服务器在发生什么

    云服务器遭受攻击时可能会出现以下问题 服务器瘫痪 攻击者可能会使用分布式拒绝服务 DDoS 攻击来使服务器无法响应请求 从而导致网站或应用程序无法正常运行 数据泄露 攻击者可能会窃取服务器上的敏感数据 例如用户名 密码或个人信息 服务器被入
  • 怎么使用Groovy+Spock做单元测试?

    1 背景 平时我们写代码 免不了要进行一些测试 如果没有使用单元测试 对于简单的程序 我们可以写一个main方法 调试查看指定的方法是否符合预期 对于一个服务系统 我们可以使用PostMan等工具来模拟一下真实请求 查看输入输出是否符合预期