类型安全的 StrictYAML Python 集成测试框架。使用此框架,您的测试可以
从程序输出(命令行测试示例)中重写自身
自动生成文档(网站测试示例)
这些测试可以单独运行或作为 pytest 测试运行。
带有演示测试的演示项目
项目 | Storytests | Python 代码 | 文档模板 | 自动生成的文档 |
---|---|---|---|---|
网站 | 添加待办事项、更正我的拼写 | engine.py | docstory.yml | 添加待办事项、更正我的拼写 |
REST API | 添加待办事项、更正我的拼写 | engine.py | docstory.yml | 添加待办事项、更正我的拼写 |
交互式命令行应用程序 | 添加待办事项、更正我的拼写 | test_integration.py | docstory.yml | 添加待办事项、更正我的拼写 |
一个 Python API | 添加待办事项、更正我的拼写 | test_integration.py | docstory.yml | 添加待办事项、更正我的拼写 |
代码示例
example.story
Logged in:
given:
website: /login # preconditions
steps:
- Form filled:
username: AzureDiamond
password: hunter2
- Clicked: login
Email sent:
about: |
The most basic email with no subject, cc or bcc
set.
based on: logged in # inherits from and continues from test above
following steps:
- Clicked: new email
- Form filled:
to: [email protected]
contents: | # long form text
Hey guys,
I think I got hacked!
- Clicked: send email
- Email was sent
from hitchstory import BaseEngine, GivenDefinition, GivenProperty
from hitchstory import Failure, strings_match
from strictyaml import Str
class Engine(BaseEngine):
given_definition = GivenDefinition(
website=GivenProperty(Str()),
)
def __init__(self, rewrite=False):
self._rewrite = rewrite
def set_up(self):
print(f"Load web page at {self.given['website']}")
def form_filled(self, **textboxes):
for name, contents in sorted(textboxes.items()):
print(f"Put {contents} in name")
def clicked(self, name):
print(f"Click on {name}")
def failing_step(self):
raise Failure("This was not supposed to happen")
def error_message_displayed(self, expected_message):
"""Demonstrates steps that can rewrite themselves."""
actual_message = "error message!"
try:
strings_match(expected_message, actual_message)
except Failure:
if self._rewrite:
self.current_step.rewrite("expected_message").to(actual_message)
else:
raise
def email_was_sent(self):
print("Check email was sent!")
>>> from hitchstory import StoryCollection
>>> from pathlib import Path
>>> from engine import Engine
>>>
>>> StoryCollection(Path(".").glob("*.story"), Engine()).named("Email sent").play()
RUNNING Email sent in /path/to/working/example.story ... Load web page at /login
Put hunter2 in name
Put AzureDiamond in name
Click on login
Click on new email
Put Hey guys,
I think I got hacked!
in name
Put Cthon98@aol.com in name
Click on send email
Check email was sent!
SUCCESS in 0.1 seconds.
安装
$ pip install hitchstory
社区
如果您在以下地方提出问题,可以获得帮助:Github 讨论 | Github 问题(不限于 bug) | Slack 频道
使用 HitchStory
本库的每个功能都已记录,并在下方列出。它使用自身进行测试和记录。
使用 HitchStory:与 Pytest 结合使用
如果您已经设置了 pytest,您可以快速轻松地使用 hitchstory 编写测试,并在您的其他 pytest 测试中运行。
使用 HitchStory:引擎
如何使用故事引擎的不同功能
- 隐藏预期异常的堆栈跟踪
- 给定前提条件
- 故事步骤的逐步类型化
- 匹配两个 JSON 片段
- 匹配两个字符串并在失败时显示差异
- 额外的故事元数据 - 例如将 JIRA 票证号添加到故事
- 带有参数的故事
- 重写给定前提条件的故事
- 重写自身的故事
- 重写参数子键的故事
- 引发 Failure 异常以隐藏堆栈跟踪
- 步骤参数
- 强类型
使用 HitchStory:文档生成
如何从您的测试中自动生成文档
使用 HitchStory:继承
从彼此继承故事
使用 HitchStory:运行器
以不同的方式运行故事
使用 HitchStory 的方法
最佳实践、工具的使用意图等。
- HitchStory 是一个 BDD 工具吗?如何使用 hitchstory 进行 BDD?
- 补充工具
- 领域特定场景语言 (DASL)
- 可执行规范
- 不稳定测试
- 封闭式端到端测试模式
- 反模式 - 分析人员为开发人员编写故事
- 测试关注点的分离
- 快照测试驱动开发 (STDD)
- 测试工件环境隔离
- 测试关注点泄露
- 测试作为一项投资
- 测试和故事有什么区别?
- 测试现实性的重要性
- 测试非确定性代码
- 规范文档测试三元组
设计决策和原则
设计决策在此处得到证明
- 声明式用户故事
- 为什么 hitchstory 强制使用 given 而不是 when 和 then?
- 为什么继承是 hitchstory 故事的一个特性?
- 为什么 hitchstory 对什么对“业务”来说有趣没有意见?
- 为什么 hitchstory 没有命令行界面?
- 原则
- 为什么 HitchStory 没有 CLI 运行器 - 只有纯 Python API?
- 为什么选择可重写测试驱动开发 (RTDD)?
- 为什么 HitchStory 使用 StrictYAML?
为什么不使用 X 而不是?
HitchStory 不是唯一一个集成测试框架。以下是它与其他框架的比较。
- 为什么使用 Hitchstory 而不是 Behave、Lettuce 或 Cucumber (Gherkin)?
- 为什么不使用 Robot Framework?
- 为什么使用 hitchstory 而不是单元测试框架?
使用 HitchStory:单独设置
如果您想在没有 pytest 的情况下使用 HitchStory
使用 HitchStory:行为
有关框架行为的杂项文档