我们已经意识到,在定义典型的 CRUD 场景时,有两种指定测试数据的选项:
选项 1:描述要使用的数据,并让实现定义数据
Scenario: Create a region
Given I have navigated to the "Create Region" page
And I have typed in a valid name
And I have typed in a valid code
When I click the "Save" button
Then I should be on the "Regions" page
And the page should show the created region details
选项 2:明确说明要使用的测试数据
Scenario: Create a region
Given I have navigated to the "Create Region" page
And I have filled out the form as follows
| Label | Value |
| Name | Europe |
| Code | EUR |
When I click the "Save" button
Then I should be on the "Regions" page
And the page should show the following fields
| Name | Code |
| Europe | EUR |
就优缺点而言,我们已经确定的是:
选项 1 很好地涵盖了“有效名称”的定义发生变化时的情况。如果我们采用选项 2(测试数据分布在多个位置),这可能会更难以处理。选项 1 明确描述了此测试的数据的重要性,尤其是在我们说“输入了无效的信用卡号”之类的情况下。它也“感觉”更加抽象和 BDD,更关心描述而不是实现。
然而,选项 1 使用非常具体的步骤,很难重复使用。例如,“页面应显示创建的区域详细信息”可能仅在此场景中使用。相反,我们可以实现选项 2 的“页面应显示以下字段”,使其可以被其他场景多次重复使用。
我还认为选项 2 似乎对客户更友好,因为他们可以通过示例看到正在发生的事情,而不必解释更抽象的术语,例如“有效”。选项 2 会更脆弱吗?重构模型可能意味着破坏这些测试,而如果测试数据是在代码中定义的,编译器将帮助我们更改模型。
我知道这里不会有正确或错误的答案,但想听听人们关于如何决定使用哪个的意见。
谢谢!
We've come to a point where we've realised that there are two options for specifying test data when defining a typical CRUD scenario:
Option 1: Describe the data to use, and let the implementation define the data
Scenario: Create a region
Given I have navigated to the "Create Region" page
And I have typed in a valid name
And I have typed in a valid code
When I click the "Save" button
Then I should be on the "Regions" page
And the page should show the created region details
Option 2: Explicitly state the test data to use
Scenario: Create a region
Given I have navigated to the "Create Region" page
And I have filled out the form as follows
| Label | Value |
| Name | Europe |
| Code | EUR |
When I click the "Save" button
Then I should be on the "Regions" page
And the page should show the following fields
| Name | Code |
| Europe | EUR |
In terms of benefits and drawbacks, what we've established is that:
Option 1 nicely covers the case when the definition of say a "valid name" changes. This could be more difficult to deal with if we went with Option 2 where the test data is in several places. Option 1 explicitly describes what's important about the data for this test, especially if it were a scenario where we were saying something like "has typed in an invalid credit card number". It also "feels" more abstract and BDD somehow, being more concerned with description than implementation.
However, Option 1 uses very specific steps which would be hard to re-use. For example "the page should show the created region details" will probably only ever be used by this scenario. Conversely we could implement Option 2's "the page should show the following fields" in a way that it could be re-used many times by other scenarios.
I also think Option 2 seems more client-friendly, as they can see by example what's happening rather than having to interpret more abstract terms such as "valid". Would Option 2 be more brittle though? Refactoring the model might mean breaking these tests, whereas if the test data is defined in code the compiler will help us with model changes.
I appreciate that there won't be a right or wrong answer here, but would like to hear people's opinions on how they would decide which to use.
Thanks!
发布评论
评论(4)
我想说这要看情况。有时,场景可能需要大量数据才能成功运行。通常,大多数数据对于我们实际测试的事物并不重要,因此会成为噪音,分散我们对场景的理解。我开始使用一种称为默认数据模式的东西来提供可以与特定于场景的数据合并的默认数据。我在这里写过:
我希望这会有所帮助。
I would say it depends. There are times when a Scenario might require a large amount of data to complete a successful run. Often the majority of that data is not important to the thing we are actually testing and therefore becomes noise distracting from the understanding we are trying to achieve with the Scenario. I started using something I call a Default Data pattern to provide default data that can be merged with data specific to the Scenario. I have written about it here:
I hope this helps.
我更喜欢选项 2。
对于业务用户来说,可以立即清楚输入是什么和输出是什么。对于选项 1,我们不知道什么是有效数据,因此您的实现可能是错误的。
在适当的时候,您还可以通过添加无效数据来更具表现力。
但是,您应该保留数据,使其按照领域而不是具体实现进行描述。这将允许您在应用程序的不同层进行测试。例如 UI 服务等。
I prefer option 2.
To the business user it is immediately clear what the inputs are and the outputs. With option 1 we don't know what valid data is, so your implementation may be wrong.
You can be even more expressive by adding invalid data too, when appropriate
You should however keep the data so its described in terms of the domain, rather that the specific implementation. This will allow you to test at different layers in your application. e.g. UI Service etc..
每次想到这个我都会改变主意。但如果你想一想 - 测试是为了证明你可以创建一个区域。两个选项都满足的标准。但我同意选项 2 的视觉提示和开发人员友好性可能太好了,无法拒绝。至少在这样的例子中是这样。
Every time I think about this I change my mind. But if you think about it - the test is to prove that you can create a region. A Criteria met by both options. But I agree that the visual cues with option 2 and developer friendliness are probably too good to turn down. In examples like this, at least.
我建议你退后一步,问问你想用这些场景来说明什么故事和规则。如果存在有关区域代码有效或无效的规则,并且您的利益相关者希望使用 BDD 来描述这些规则,那么您可以使用有效和无效区域代码的具体示例。如果你想描述一个区域创建后会发生什么,那么确切的数据就没那么有趣了。
您的“创建区域”实际上并不是我们在 BDD 中使用的典型场景。它可以被描述为“当我创造一个东西时,我就能看到它”。这不是一个有用的场景,因为它本身不能为用户提供任何有价值的东西。我们寻找向最终用户交付有趣或有价值的东西的场景。用户为什么要创建一个区域?最终目标是什么?这样另一个用户就可以将其他对象分配给该区域,也许?
示例映射,其中故事与规则和示例链接(其中示例成为场景),在 https://cucumber.io/blog/bdd/example-mapping-introduction/
I would suggest you take a step back and ask what stories and rules you are trying to illustrate with these scenarios. If there are rules about what makes a valid or invalid region code, and your stakeholders want to describe those using BDD, then you can use specific examples of valid and invalid region codes. If you want to describe what can happen after a region is created, then the exact data is not so interesting.
Your "Create a region" is not actually typical of the scenarios that we use in BDD. It can be characterised as "when I create a thing, then I can see the thing". It's not a useful scenario in that it doesn't by itself deliver anything valuable to the user. We look for scenarios in which something interesting or valuable is delivered to the end-user. Why is the user creating a region? What is the end goal? So that another user can assign other objects to that region, perhaps?
Example mapping, where stories are linked with rules and examples (where the examples become scenarios), is described in https://cucumber.io/blog/bdd/example-mapping-introduction/