- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
模型驱动的自动化测试(Model-Based Testing, 后文中我们将简称为MBT)是一种软件测试方法,它将系统的行为表示为一个或多个模型,然后从模型中自动生成和执行测试用例。这种方法的核心思想是将测试过程中的重点从手动编写测试用例转移到创建和维护描述系统行为的模型.
基于MBT的测试相比较于普通的测试有以下几大优点:
优点 | 描述 |
---|---|
覆盖率 | 模型是对系统行为的抽象表示,可以帮助测试人员更好地理解和分析系统的功能和性能。从而提高测试覆盖率。 |
测试效率 | 通过从模型中自动生成测试用例,减少手动编写测试用例的工作量,提高测试效率。 |
可维护性 | 模型驱动的测试用例易于维护,因为当系统发生变化时,只需更新模型,而无需手动修改大量测试用例。 |
可重用性 | 模型可以在多个测试项目中重用,减少重复工作并提高测试质量。 |
基于MBT的测试主要有以下几个步骤:
创建模型: 首先,需要构建一个描述系统行为的模型。这个模型通常采用图形表示,如状态机、Petri网或者流程图等。模型中的顶点表示系统的状态,边表示状态之间的转换.
生成测试用例: 通过分析模型,可以自动生成测试用例。测试用例生成算法可以根据不同的目标(如覆盖率、路径长度等)来选择。常用的算法有随机测试、覆盖所有路径、覆盖所有边等.
执行测试: 使用自动生成的测试用例对实际系统进行测试。这一步通常需要一个测试执行引擎,它可以将模型中的操作映射到实际系统中的操作。例如,使用Selenium WebDriver进行Web应用测试.
验证结果: 比较实际系统的行为与模型的预期行为,以确定系统是否满足需求。如果发现问题,可以更新模型并重新生成测试用例.
下面我们一起来看看在实际业务中使用 AltWalker 库进行进行基于模型的自动化测试的应用.
AltWalker 是一个基于图模型的自动化测试框架,用于编写、执行和管理基于模型的测试。它主要用于测试复杂系统,如Web应用程序、移动应用程序等。它支持运行用 .NET/C# 和 Python3 编写测试模型用例.
在命令行中输入以下命令来安装AltWalker:
pip install altwalker
$ altwalker --version
AltWalker, version 0.3.1
创建一个新的文件夹,用于存放我们的测试项目。在该文件夹中,执行以下命令创建 MBT :
altwalker init -l python test-project
执行这个命令后,将在当前目录生成一个包含模型模板代码的目录 test-project ,目录结构如下:
# tree
test-project/
├── models/
│ ├── default.json
└── tests/
├── __init__.py
└── test.py
只需要执行以下命令,就能够运行 default.json 中定义的模型,覆盖模型的链路,链路执行时会运行对应在 test.py 中的代码 :
$ cd test-project
$ altwalker online tests -m models/default.json "random(edge_coverage(100))"
上面只是执行了一个单一的链路Demo,下面我们一起写一个我们自己的模型.
模型编辑器我们可以选择在线的,也可以选择使用 vscode 的插件,当然也可以选择自己搭建一个.
我们可以使用在线的 模型编辑器 来编写模型.
可以在扩展上搜索 AltWalker Model Visualizer ,也可以自己访问链接下载 扩展 来编辑查看模型.
可以参考: https://github.com/altwalker/model-editor 。
{
"name": "Pay Models",
"models": [
{
"name": "PayModel",
"generator": "random(edge_coverage(100) && vertex_coverage(100))",
"startElementId": "v_init",
"vertices": [
{
"id": "v_init",
"name": "start_vertex"
},
{
"id": "v_login",
"name": "state_login"
},
{
"id": "v_select_product",
"name": "state_select_product"
},
{
"id": "v_pay",
"name": "state_pay"
},
{
"id": "v_logout",
"name": "state_logout"
}
],
"edges": [
{
"id": "e_init",
"name": "action_init",
"sourceVertexId": "v_init",
"targetVertexId": "v_login"
},
{
"id": "e_login",
"name": "action_login",
"sourceVertexId": "v_login",
"targetVertexId": "v_select_product"
},
{
"id": "e_select_product",
"name": "action_select_product",
"sourceVertexId": "v_select_product",
"targetVertexId": "v_pay"
},
{
"id": "e_pay",
"name": "action_pay",
"sourceVertexId": "v_pay",
"targetVertexId": "v_logout"
},
{
"id": "e_logout",
"name": "action_logout",
"sourceVertexId": "v_logout",
"targetVertexId": "v_init"
}
]
}
]
}
保存这个模型到新创建的项目 default.json ,然后执行下面的命令检查模型是否存在问题:
altwalker check -m models/default.json "random(never)"
altwalker check -m models/default.json "random(never)"
因为我们还没有编写测试代码,所以会出现下面的报错:
可以看到在上面的报错中给出了建议的代码,我们把它复制到 test.py 中.
class PayModel:
def state_pay(self):
pass
def action_init(self):
pass
def state_select_product(self):
pass
def state_logout(self):
pass
...
在命令行中执行下面的命令来执行测试:
altwalker online tests -m models/default.json "random(edge_coverage(100))" --report-xml-file report.xml
这将会运行在 default.json 和 test.py 文件中定义的所有测试用例.
在测试执行完成后,AltWalker会生成一个名为 report.xml 的JUnit格式的测试报告。我们可以使用任何支持JUnit格式的测试报告工具来查看这个报告.
还有其他方式的测试报告提供,可以查看官方文档.
如果我们有一个商城需要验证,有登录、用户个人中心,商品首页,商品详情页、支付界面、订单界面等,我们要针对这样的网站做一个自动化,可能会有以下这些场景:
场景 |
---|
登录界面 -> Do:输入密码登录 -> 用户首页 -> Do:查看商品A -> A商品详情页 -> Do:点击第二个商品按钮 -> 商品C详情页面 -> Do:点击付款 -> 付款界面 -> Do:取消付款 -> 订单倒计时界面 -> Do:关闭浏览器 -> 浏览器关闭 |
登录界面 -> Do:输入密码登录 -> 用户首页 -> Do:查看商品A -> A商品详情页 -> Do:点击第二个商品按钮 -> 商品C详情页面 -> Do:点击付款 -> 付款界面 -> Do:查看订单 -> 历史订单界面 -> Do:关闭浏览器 -> 浏览器关闭 |
登录界面 -> Do:输入密码登录 -> 用户首页 -> Do:查看商品A -> A商品详情页 -> Do:点击第二个商品按钮 -> 商品C详情页面 -> Do:点击付款 -> 付款界面 -> Do:查看订单 -> 历史订单界面 -> Do:查看订单详情 -> 订单详情界面 -> Do:关闭浏览器 -> 浏览器关闭 |
登录界面 -> Do:输入密码登录 -> 用户首页 -> Do:查看商品A -> A商品详情页 -> Do:点击第二个商品按钮 -> 商品C详情页面 -> Do:点击用户中心 -> 用户中心界面 -> Do:查看订单 -> 历史订单界面 -> Do:关闭浏览器 -> 浏览器关闭 |
登录界面 -> Do:输入密码登录 -> 用户首页 -> Do:查看商品A -> A商品详情页 -> Do:点击第二个商品按钮 -> 商品C详情页面 -> Do:点击用户中心 -> 用户中心界面 -> Do:查看订单 -> 历史订单界面 -> Do:查看订单详情 -> 订单详情界面 -> Do:关闭浏览器 -> 浏览器关闭 |
登录界面 -> Do:输入密码登录 -> 用户首页 -> Do:查看商品A -> A商品详情页 -> Do:点击相似商品B -> 商品B详情页 -> Do:点击购买 -> 付款界面 -> Do:取消付款 -> 订单倒计时界面 -> Do:关闭浏览器 -> 浏览器关闭 |
登录界面 -> Do:输入密码登录 -> 用户首页 -> Do:查看商品A -> A商品详情页 -> Do:点击相似商品B -> 商品B详情页 -> Do:点击购买 -> 付款界面 -> Do:查看订单 -> 历史订单界面 -> Do:关闭浏览器 -> 浏览器关闭 |
登录界面 -> Do:输入密码登录 -> 用户首页 -> Do:查看商品A -> A商品详情页 -> Do:点击相似商品B -> 商品B详情页 -> Do:点击购买 -> 付款界面 -> Do:查看订单 -> 历史订单界面 -> Do:查看订单详情 -> 订单详情界面 -> Do:关闭浏览器 -> 浏览器关闭 |
... |
大家应该都能发现,使用 altwalker 画出来的图,能非常直观的展示各个页面之间可以进行的操作,并且很好扩展,这非常符合我们做页面自动化的时候所说的 POM (Page Object Model).
这也是altwalker最重要的价值所在: 适合的用于测试复杂系统,如Web应用程序、移动应用程序等.
{
"name": "Default Models",
"models": [
{
"name": "DefaultModel",
"generator": "random(never)",
"startElementId": "v0",
"vertices": [
{
"id": "v0",
"name": "登录界面"
},
{
"id": "v1",
"name": "用户首页"
},
{
"id": "v2",
"name": "浏览器关闭"
},
{
"id": "v3",
"name": "A商品详情页"
},
{
"id": "v6",
"name": "商品C详情页面"
},
{
"id": "v7",
"name": "付款界面"
},
{
"id": "v8",
"name": "付款成功界面"
},
{
"id": "v9",
"name": "订单倒计时界面"
},
{
"id": "v10",
"name": "用户中心界面"
},
{
"id": "v11",
"name": "商品B详情页"
},
{
"id": "v4",
"name": "历史订单界面"
},
{
"id": "v5",
"name": "订单详情界面"
}
],
"edges": [
{
"id": "e0",
"name": "输入密码登录",
"sourceVertexId": "v0",
"targetVertexId": "v1"
},
{
"id": "e1",
"name": "关闭浏览器",
"sourceVertexId": "v0",
"targetVertexId": "v2"
},
{
"id": "e2",
"name": "关闭浏览器",
"sourceVertexId": "v1",
"targetVertexId": "v2"
},
{
"id": "e3",
"name": "查看商品A",
"sourceVertexId": "v1",
"targetVertexId": "v3"
},
{
"id": "e5",
"name": "点击第二个商品按钮",
"sourceVertexId": "v3",
"targetVertexId": "v6"
},
{
"id": "e7",
"name": "点击付款",
"sourceVertexId": "v6",
"targetVertexId": "v7"
},
{
"id": "e8",
"name": "退出登录",
"sourceVertexId": "v8",
"targetVertexId": "v0"
},
{
"id": "e9",
"name": "e9",
"sourceVertexId": "v3",
"targetVertexId": "v8"
},
{
"id": "e10",
"name": "付款成功",
"sourceVertexId": "v7",
"targetVertexId": "v8"
},
{
"id": "e11",
"name": "取消付款",
"sourceVertexId": "v7",
"targetVertexId": "v9"
},
{
"id": "e12",
"name": "点击用户中心",
"sourceVertexId": "v6",
"targetVertexId": "v10"
},
{
"id": "e13",
"name": "点击购买",
"sourceVertexId": "v11",
"targetVertexId": "v7"
},
{
"id": "e14",
"name": "点击相似商品B",
"sourceVertexId": "v3",
"targetVertexId": "v11"
},
{
"id": "e17",
"name": "关闭浏览器",
"sourceVertexId": "v9",
"targetVertexId": "v2"
},
{
"id": "e18",
"sourceVertexId": "v10",
"targetVertexId": "v4",
"name": "查看订单"
},
{
"id": "e19",
"name": "点击首页按钮",
"sourceVertexId": "v3",
"targetVertexId": "v1"
},
{
"id": "e20",
"name": "点击首页",
"sourceVertexId": "v6",
"targetVertexId": "v1"
},
{
"id": "e21",
"name": "点击用户中心",
"sourceVertexId": "v10",
"targetVertexId": "v1"
},
{
"id": "e4",
"name": "刷新浏览器",
"sourceVertexId": "v6",
"targetVertexId": "v6"
},
{
"id": "e6",
"name": "查看订单",
"sourceVertexId": "v7",
"targetVertexId": "v4"
},
{
"id": "e15",
"name": "关闭浏览器",
"sourceVertexId": "v4",
"targetVertexId": "v2"
},
{
"id": "e16",
"name": "查看订单详情",
"sourceVertexId": "v4",
"targetVertexId": "v5"
},
{
"id": "e22",
"name": "关闭浏览器",
"sourceVertexId": "v5",
"targetVertexId": "v2"
}
],
"actions": [
"fasf;fdsaf;"
]
}
]
}
完整的结合 POM 使用的方法可以查看官方给出的示例: https://github.com/altwalker/altwalker-examples 。
如果我们仅仅只想使用模型中的链路组织能力,也可以自己根据编写的模型使用下面这段代码来生成对应的链路,然后组织用例场景,可以用于自动化用例生成.
graph_data = {
"name": "Default Models",
"models": [
{
"name": "DefaultModel",
"generator": "random(never)",
"startElementId": "v0",
"vertices": [
{
"id": "v0",
"name": "登录界面"
...
]
}
model = graph_data['models'][0]
edges = model['edges']
vertices = model['vertices']
start_vertex_id = model['startElementId']
# 构建图
graph = {}
for edge in edges:
source = edge['sourceVertexId']
target = edge['targetVertexId']
if source not in graph:
graph[source] = []
graph[source].append((target, edge['name']))
# 顶点ID到顶点名称的映射
vertex_name_map = {vertex['id']: vertex['name'] for vertex in vertices}
# 深度优先搜索
def dfs(_graph, start_vertex, _path, _visited):
_visited.add(start_vertex)
_path.append(vertex_name_map[start_vertex])
if start_vertex not in _graph:
print(" -> ".join(_path))
else:
for neighbor, action in _graph[start_vertex]:
if neighbor not in _visited:
_path.append(f"Do:{action}")
dfs(_graph, neighbor, _path, _visited)
_path.pop()
_path.pop()
_visited.remove(start_vertex)
# 打印所有可能的链路及其经过的操作,操作前面加上"Do"标记
visited = set()
path = []
dfs(graph, start_vertex_id, path, visited)
通过以上步骤,我们了解了如何使用AltWalker进行模型驱动的自动化测试。AltWalker是一个强大的测试框架,可以帮助我们更高效地编写、执行和管理测试用例.
当然,基于模型的测试也有一些局限性,如模型的准确性和完整性对测试结果影响较大,模型构建和维护可能需要额外的成本等。 因此,在实际应用中,需要根据项目的具体需求来决定是否采用基于模型的测试方法。希望本文对你有所帮助! 。
最后此篇关于【AltWalker】模型驱动:轻松实现自动化测试用例的生成和组织执行的文章就讲到这里了,如果你想了解更多关于【AltWalker】模型驱动:轻松实现自动化测试用例的生成和组织执行的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我尝试将resteasy与自定义对象一起使用,当我创建jar文件时,它与intellij IDE一起工作正常,但失败并出现以下异常 org.jboss.resteasy.core.NoMessageB
我正在寻找一种在easy-close选项为TRUE时基于Shiny模态关闭触发事件的方法(因此,在模态外部单击将其关闭)。由于没有链接到模式的ID,因此我似乎无法捕获此事件。我尝试在“观察”事件中包装
假设我有一些定义如下的类: class Security { Boolean AuthenticateUser(String username, String password); B
正如标题所说,Coq 可以用作模型检查器吗?我可以将模型检查与 Coq 证明混合使用吗?这是常态吗?谷歌谈论“微积分”,有没有人有这方面的经验或类似的经验?是否建议以这种方式使用 Coq,或者我应该寻
是否有一种方法(设置或快捷方式)可以显示输出超过 500 行的查询的总行数 - 即,无需修改首选项中的“结果集页面大小”值?我本质上是在寻找 select count(*) from () t 的输出
我想这样做: System.out.println("안녕하세요!"); 但是当我尝试在 Eclipse 中进行编译时,出现“某些字符无法使用 MacRoman 字符编码进行编码”弹出式错误消息。我正
如果我有一个用这样的字符串初始化的框架 setter CTFramesetterRef framesetter = CTFramesetterCreateWithAttributedString(at
所以这里没有什么新内容,我只是想得到一些澄清,但似乎在其他帖子中找不到任何澄清。 我正在安静地创建一个新资源,例如: /books (POST) 有一个 body : { title: 'The
我有很多预处理器宏定义,如下所示: #define FOO 1 #define BAR 2 #define BAZ 3 在实际应用中,每个定义对应一个解释器虚拟机中的一条指令。宏的编号也不是连续的,以
使用 SpriteKit 开发 iOS 游戏。我的背景由 map block 组成(本质上是无限 map ,程序生成)。 我们的系统旨在管理 map 的“ block ”,我们只加载玩家附近的 blo
我需要在 Ruby 中拆分一个具有以下格式的字符串: [{a:1,b:2,c:3,d:4},{a:5,b:6,c:7,d:8},{a:9,b:10,c:11,d:12},{a:13,b:14,c:1
Linq 有一个名为 Take() 的便捷运算符方法,可以返回任何实现 IEnumerable 的元素中给定数量的元素。 jQuery 中是否有类似的东西可以处理数组? 或者,换个方式问:如何在 Ja
每当我使用以下代码在文档中插入图像时, var cursor = DocumentApp.getActiveDocument().getCursor(); var image = cursor
今天看到这样一段代码: if ( not defined($reply_address) or not defined($from_name) or not defined(
这个问题不太可能帮助任何 future 的访问者;它只与一个小的地理区域、一个特定的时间点或一个非常狭窄的情况有关,这些情况并不普遍适用于互联网的全局受众。为了帮助使这个问题更广泛地适用,visit
刚刚了解 mercurial 的 --style和 --template可用于 hg log 的选项和 hg tip我发现它们非常有帮助,但我不知道把我的“样式文件”放在哪里 我有一个“样式文件”,它
是否有一些应用程序可以自动 bundle (并缩小)包含 require('file.js') 调用的 JS 项目?这样它们就会合并并生成一个文件。 具体来说,我正在谈论when.js ,一个带有大量
如何(轻松)获取 Sublime Text 3 中的当前文件路径 我不经常使用 ST 控制台(我只使用它一次来安装包管理器),但我认为这可能是一个好方法: 像某种pwd命令一样获取当前文件路径。 但这
嗨,我正在使用resteasy api,我需要使用Map作为QueryParam。我可以使用列表作为 QueryParam,但是当我尝试传递 Map 时,我收到下面提到的错误。 这是我的服务代码 @G
假设我有一个 C++ 代码(请参阅下面的简单示例)。我想让期刊审稿人轻松安装/运行 所以我认为最简单的方法是将其变形为简化的类 R 包的 tar.gz 文件,以便裁判可以安装它通过简单地调用 inst
我是一名优秀的程序员,十分优秀!