惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Exploit-DB.com RSS Feed
Exploit-DB.com RSS Feed
Blog — PlanetScale
Blog — PlanetScale
GbyAI
GbyAI
Engineering at Meta
Engineering at Meta
博客园 - 司徒正美
T
Tailwind CSS Blog
F
Full Disclosure
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
小众软件
小众软件
IT之家
IT之家
J
Java Code Geeks
Y
Y Combinator Blog
Microsoft Security Blog
Microsoft Security Blog
B
Blog
V
V2EX
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Hugging Face - Blog
Hugging Face - Blog
美团技术团队
The Cloudflare Blog
Recent Announcements
Recent Announcements
博客园 - 【当耐特】
Google DeepMind News
Google DeepMind News
罗磊的独立博客
博客园 - 叶小钗
阮一峰的网络日志
阮一峰的网络日志
The GitHub Blog
The GitHub Blog
云风的 BLOG
云风的 BLOG
aimingoo的专栏
aimingoo的专栏
大猫的无限游戏
大猫的无限游戏
酷 壳 – CoolShell
酷 壳 – CoolShell
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
S
Security @ Cisco Blogs
MyScale Blog
MyScale Blog
MongoDB | Blog
MongoDB | Blog
U
Unit 42
H
Heimdal Security Blog
Recent Commits to openclaw:main
Recent Commits to openclaw:main
V2EX - 技术
V2EX - 技术
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Google Online Security Blog
Google Online Security Blog
N
News and Events Feed by Topic
Hacker News - Newest:
Hacker News - Newest: "LLM"
PCI Perspectives
PCI Perspectives
博客园 - 三生石上(FineUI控件)
I
InfoQ
SecWiki News
SecWiki News
N
News and Events Feed by Topic
D
DataBreaches.Net
Schneier on Security
Schneier on Security
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO

浮华生

Elasticsearch 检索性能优化 - 浮华生 舆情监控系统综述 - 浮华生 2024 半年度总结 - 浮华生 2023 年终总结 - 浮华生 异地机器组网方案 - 浮华生 Kubernetes 部署 Elasticsearch 和 Kibana - 浮华生 2022 年终总结 - 浮华生 RabbitMQ connection channel 的关系 - 浮华生 Kafka Java 客户端 Producer 原理分析 - 浮华生 RabbitMQ 和 Kafka 应用原理简单对比 - 浮华生 阿里云 OpenSearch 介绍 - 浮华生 Golang Array 和 Slice 区别 - 浮华生 Mac OS 下打造 golang nvim 编程环境之基础配置 - 浮华生 电商搜索技术总结 - 浮华生 电商搜索业务总结 - 浮华生 2021 年终总结 - 浮华生 Cypress 实践总结 - 浮华生 年终总结 - 浮华生 关于我 - 浮华生 微服务应用集成 SpringCloud 步骤 - 浮华生 电商搜索数据同步方案 - 浮华生 通过一道数值转换题重温计算机补码 - 浮华生 macOS 系统推荐的一些软件 - 浮华生 DevOps 实施规划(持续更新) - 浮华生 rabbitmq 如何提高可靠性并保证消费端幂等 - 浮华生 AMQ Model总结 - 浮华生 结对编程 - 浮华生 RSocket 介绍 - 浮华生 面向对象的理解 - 浮华生 企业平台技术框架 - 浮华生 对创业的思考 - 浮华生 知难行易 - 浮华生 一年工作经验总结 - 浮华生 我与领域驱动之缘 - 浮华生 TDD 中使用的工具 - 浮华生 tf-idf 算法 - 浮华生 gitlab 添加代码规范检测 - 浮华生 query 改写 - 浮华生 阶段性总结 - 浮华生 操作系统作用 - 浮华生 - 浮华生 hamming-distance - 浮华生 ElasticSearch API 基本操作 - 浮华生 elasticsearch 集群容错 - 浮华生 ElasticSearch 基础概念 - 浮华生 技术选型怎么做 - 浮华生 条件概率、全概率与贝叶斯公式 - 浮华生 年终总结 - 浮华生 迁移到 ubuntu18 的问题及配置 - 浮华生 总结 - 浮华生 使用 psi-probe 监控 Tomcat - 浮华生 Tomcat 远程 Debug - 浮华生 jstack 死循环和死锁定位 - 浮华生 jmap & mat 内存溢出 - 浮华生 JVM 常用参数查看 - 浮华生 周总结(8.13-8.19) - 浮华生 周总结(7.30-8.4) - 浮华生 使用移位运算符 - 浮华生 master 公式 - 浮华生 VMware 12 NAT网络下配置 ubuntu 16.04 LTS 系统静态 IP - 浮华生 关于进制的计算 - 浮华生 项目总结 第三篇 - 浮华生 项目总结 第二篇 - 浮华生 editor.md 富文本编辑器的使用 - 浮华生 项目总结 第一篇 - 浮华生 2017至今总结 - 浮华生 谈谈微服务 - 浮华生 单例模式 - 浮华生 tor 使用 - 浮华生 归档 - 浮华生 搜索 - 浮华生 搜索 && 推荐 - 浮华生
使用 cucumber 进行行为驱动开发(BDD) - 浮华生
浮华生 · 2020-10-20 · via 浮华生

前言

保证软件质量的方式多种多样,根据测试金字塔上所描绘的,单元测试是最有效的,但是在公司内部实践的时候却遇到了一些问题,比如赶进度来不及写单元测试、改了代码逻辑单元测试也需要跟着变、验收时同样会有很多 bug,总结下来大概有几个原因:

  • 需求分析时有很多细节没有考虑到(这个不可避免)
  • 测试用例覆盖的场景不全
  • 分层架构需要对每一层都进行测试,会占用大量时间

还有一个原因是公司技术环境,我司是业务驱动的,主营业务在线下,最有价值是业务而非技术。

综合多方面的原因,决定尝试 BDD 的测试方式,这样做的好处可以分为以下几点:

  • 活文档,好的用例能够体现业务的整个面貌
  • 将关注点放到更有价值的业务上来,而非技术
  • 对于目前团队现状,BDD 的投入产出比要比单元测试更好

步骤

用户登录的用户故事举例:

作为一名供应商,我希望在输入用户名:”admin“,密码:“admin” 后能够进到系统首页,然后能够进行数据操作

验收标准:
 场景1:用户名密码正确
  Given:用户名:admin,密码:admin
  When:我在登录页上输入用户名 admin 和密码 admin
  Then:我将进入到系统首页
  
 场景2:用户名或密码不正确
 Given:用户名:admin,密码:admin
 When:我在登录页上输入用户名 admin 和密码 admin123
 Then:我被告知 “用户名或者密码错误”
 AND:此时我还是未登录状态
 

注意:对于用户故事验收标准这部分应该以用户行为为主,避免UI操作的字段出现,比如“我点击了提交按钮”,这样是不推荐的。

添加依赖

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
<dependency>
    <groupId>io.cucumber</groupId>
    <artifactId>cucumber-java</artifactId>
    <version>${cucumber.version}</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>io.cucumber</groupId>
    <artifactId>cucumber-junit</artifactId>
    <version>${cucumber.version}</version>
    <scope>test</scope>
</dependency>
<dependency>
    <groupId>io.cucumber</groupId>
    <artifactId>cucumber-spring</artifactId>
    <version>${cucumber.version}</version>
    <scope>test</scope>
</dependency>

添加 feature 文件

在 /src/test/resource 文件夹下新建 feature 文件夹,并在此文件夹中创建 login.feature 文件。

添加一个场景

1
2
3
4
5
6
7
8
9
#language: zh-CN
功能供应商登录
   场景大纲: 用户名密码正确
     假设已注册的供应商用户名密码 admin admin
     当供应商输入用户名密码<username><password>
     那么能够进入到系统首页
     例子:
     |username|password|
     |admin   |admin   |

说明:

  • #language: zh-CN 指定使用的语言
  • 功能:对应 user story 的标题
  • 场景:对应功能的其中一种情况
  • 假设、当、那么:cucumber 指定的中文 DSL,对于 Given、When、Then
  • 对于要使用变量的地方使用 < > 标注出来并在下面的例子中列出数据内容

注意:feature 中的标点符号全部为英文标点

右键运行

此时我们还未创建任何业务代码,但是还是会有高亮展示

image-20201020175455431

此时,我们右键点击会有下面的按钮

image-20201020175654194

点击运行

image-20201020175752514

因为我们还没有编写代码,所以此时测试一定会报错,那么接下来需要做的是写代码让这段测试通过

步骤定义

在 /src/test/java 下新建一个 login 的文件夹,并新建 LoginStepDef java 文件。我们的测试逻辑将在这个文件中完成。本次仅对密码正确的情况做演示

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
@CucumberContextConfiguration
public class LoginStepDef {

    private  Account account;
        @假设("^已注册的供应商用户名密码 admin admin$")
        public void setUp(){
            account = new Account("admin","admin");
        }

        @当("^供应商输入用户名密码(\\S*)(\\S*)$")
        public boolean when_input_account_info(String username,String password){
            if (account.valid(username,password)){
                return true;
            }
            return false;
        }
       @那么("^能够进入到系统首页$")
        public void get_into_index(){

       }

    }

说明:

  1. @CucumberContextConfiguration cucumber 提供的 Spring 集成注解

  2. @假设("^已注册的供应商用户名密码 admin admin$")@假设是中文的注解(中英文对照表请参见文末表格),与 feature 文件相对应。^ $ 和 shell 功能类似,代表一行的开头和结尾,固定格式。

  3. 对于需要传递参数的方法需要使用正则表达式进行占位

  • 整型 (\d+)

  • 字符串 (\S*)

  • 布尔值 (true|false)

  • 列表 使用 DataTable 举例:

    Given the following animals: | cow | | horse | | sheep |

    定义时:

    1
    2
    3
    
     @Given("the following animals:")
      public void the_following_animals(List<String> animals) {
      }
    

配置 Junit 引导

在 /src/test/java/login 中创建名为 LoginIntegerationTest 的 java 文件

1
2
3
4
5
6
@RunWith(Cucumber.class)
@CucumberOptions(features = "classpath:features/login",
        plugin = {"pretty", "html:target/cucumber/login.html"})
public class LoginIntegrationTest {
}

说明:

  1. @CucumberOptions cucumber 的配置注解
  2. features 指定 feature 文件的路径
  3. plugin 将测试结果以 html 的格式输出到指定目录

再次运行

image-20201021115138478

查看测试报告

根据配置的目录,找到对应的 html 文件

image-20201021115248832

Jenkins 集成

Github 中有开源的 Jenkins Plugin: Publish pretty cucumber-jvm reports on Jenkins

总结

如何选择合适的测试手段,需要结合企业研发团队的现状和经营模式做选型,TDD 虽然能提升质量,但并不适用所有的企业。

本文对 cucumber 做了一个基础的演示,对于复杂的环境,推荐结合 Rest Assured 对 API 做测试。

想要了解更多可以查看文末参考资料。

附表

中英文关键字的对照表

英文关键字中文关键字
feature“功能”
background“背景”
scenario“场景”, “剧本”
scenario_outline“场景大纲”, “剧本大纲”
examples“例子”
given“* “, “假如”, “假设”, “假定”
when“* “, “当”
then“* “, “那么”
and“* “, “而且”, “并且”, “同时”
but“* “, “但是”
given (code)“假如”, “假设”, “假定”
when (code)“当”
then (code)“那么”
and (code)“而且”, “并且”, “同时”
but (code)“但是”

参考资料

https://vitzhou.gitbooks.io/java-test-learning/content/cucumber/practice/chinese.html

https://vitzhou.gitbooks.io/java-test-learning/content/cucumber/practice/pass_parameters.html

https://developer.ibm.com/zh/articles/j-lo-cucumber01/

https://thepracticaldeveloper.com/cucumber-tests-spring-boot-dependency-injection/

相关书籍

Cucumber:行为驱动开发指南