在 Specflow 中,我可以执行一次设置然后 运行 一堆独立的验证作为单独的测试吗?
In Specflow can I perform setup once then run a bunch of independent verifications as separate tests?
我正在为一组 API 编写自动化测试。我有 1 API 到 运行 一个搜索和另一个获取结果。我想 运行 搜索一次,然后进行多次测试 获取结果并 运行 验证。
RunOnce:
Given I have access to the User 'testUser'
When I call POST /api/Search with
"""
{
"query": "legal",
"snippetLength": 15,
"resultSize": 4,
...
}
"""
Scenario: SearchAPI - Verify Result Size
When I call GET /api/Search
Then The result size is X
Scenario: SearchAPI - Verify Filters
When I call GET /api/Search
Then The filters are X
Scenario: SearchAPI - Verify Sorting
When I call GET /api/Search
Then The sorting is X
Scenario: SearchAPI - Verify snippet
When I call GET /api/Search
Then The snippet length is X
这是一个非常糟糕的模式吗?由于时间问题,我不想 运行 搜索每个场景。但与此同时,我希望将测试分开,这样我就不会在单个场景中拥有所有断言以进行有效的结果分析。
我认为执行此操作的唯一方法是向功能添加标记并在 TestHooks 文件中实现它。但是如果 POST 调用失败,我就会失去很多可见性。
没有允许您执行此操作的 Gherkin 语言功能。相反,请考虑使用 FeatureContext 来存储搜索结果,因为 FeatureContext 对象由功能中的所有场景共享。您仍然会为提交搜索的给定步骤使用场景背景。步骤定义将检查特征上下文是否已经有搜索结果,如果是,则 Given 步骤将什么也不做。如果特征上下文中不存在搜索结果,则执行代码以POST进行搜索。
对搜索结果进行操作的任何“何时”或“然后”步骤都应从功能上下文中提取结果。
专题文件:
Background:
Given I have access to the User 'testUser'
When I call POST /api/Search with
"""
{
"query": "legal",
"snippetLength": 15,
"resultSize": 4,
...
}
"""
Scenario: SearchAPI - Verify Result Size
When I call GET /api/Search
Then The result size is X
Scenario: SearchAPI - Verify Filters
When I call GET /api/Search
Then The filters are X
Scenario: SearchAPI - Verify Sorting
When I call GET /api/Search
Then The sorting is X
Scenario: SearchAPI - Verify snippet
When I call GET /api/Search
Then The snippet length is X
接下来,使用FeatureContext
存储和检索searchId,结果:
[Binding]
public class SearchSteps
{
private readonly FeatureContext feature;
/// <summary>
/// Gets or sets the API search Id
/// </summary>
private string SearchId
{
get => (string)feature["foo"];
set => feature["foo"] = value;
}
/// <summary>
/// Gets or sets the API search results
/// </summary>
private IEnumerable<X> Results
{
get => (IEnumerable<X>)feature["searchResults"];
set => feature["searchResults"] = value;
}
public SearchSteps(FeatureContext feature)
{
this.feature = feature;
}
[When(@"I call POST /api/Search with")]
public void WhenICallPOST_api_searchWith(string json)
{
if (SearchId != null)
return;
var request = // parse json variable into object
SearchId = api.PostSearch(request);
}
[When(@"I call GET /api/Search")]
public void WhenICallGET_api_Search()
{
Results = api.GetSearch(SearchId);
}
[Then(@"The result size is (\d+)")]
public void ThenResultSizeIs(int expectedResultSize)
{
Assert.AreEqual(Results.Count(), expectedResultSize);
}
// Other 'Then' steps make assertions on Results property
}
您可以神奇地访问 FeatureContext,因为 SpecFlow 已经使用依赖注入框架注册了该对象。只需将 FeatureContext 参数添加到步骤定义的构造函数中即可访问此对象。
我发现在 FeatureContext
对象上创建 get/set 值的私有属性很好,所以你只在一个地方投射对象。此外,它还为事物提供了一个有意义的名称,并使您在步骤定义中更容易处理 FeatureContext。
您可以将 IEnumerable<X> Results
替换为对 GET /api/Search/:searchId
的响应类型的名称。
我正在为一组 API 编写自动化测试。我有 1 API 到 运行 一个搜索和另一个获取结果。我想 运行 搜索一次,然后进行多次测试 获取结果并 运行 验证。
RunOnce:
Given I have access to the User 'testUser'
When I call POST /api/Search with
"""
{
"query": "legal",
"snippetLength": 15,
"resultSize": 4,
...
}
"""
Scenario: SearchAPI - Verify Result Size
When I call GET /api/Search
Then The result size is X
Scenario: SearchAPI - Verify Filters
When I call GET /api/Search
Then The filters are X
Scenario: SearchAPI - Verify Sorting
When I call GET /api/Search
Then The sorting is X
Scenario: SearchAPI - Verify snippet
When I call GET /api/Search
Then The snippet length is X
这是一个非常糟糕的模式吗?由于时间问题,我不想 运行 搜索每个场景。但与此同时,我希望将测试分开,这样我就不会在单个场景中拥有所有断言以进行有效的结果分析。
我认为执行此操作的唯一方法是向功能添加标记并在 TestHooks 文件中实现它。但是如果 POST 调用失败,我就会失去很多可见性。
没有允许您执行此操作的 Gherkin 语言功能。相反,请考虑使用 FeatureContext 来存储搜索结果,因为 FeatureContext 对象由功能中的所有场景共享。您仍然会为提交搜索的给定步骤使用场景背景。步骤定义将检查特征上下文是否已经有搜索结果,如果是,则 Given 步骤将什么也不做。如果特征上下文中不存在搜索结果,则执行代码以POST进行搜索。
对搜索结果进行操作的任何“何时”或“然后”步骤都应从功能上下文中提取结果。
专题文件:
Background:
Given I have access to the User 'testUser'
When I call POST /api/Search with
"""
{
"query": "legal",
"snippetLength": 15,
"resultSize": 4,
...
}
"""
Scenario: SearchAPI - Verify Result Size
When I call GET /api/Search
Then The result size is X
Scenario: SearchAPI - Verify Filters
When I call GET /api/Search
Then The filters are X
Scenario: SearchAPI - Verify Sorting
When I call GET /api/Search
Then The sorting is X
Scenario: SearchAPI - Verify snippet
When I call GET /api/Search
Then The snippet length is X
接下来,使用FeatureContext
存储和检索searchId,结果:
[Binding]
public class SearchSteps
{
private readonly FeatureContext feature;
/// <summary>
/// Gets or sets the API search Id
/// </summary>
private string SearchId
{
get => (string)feature["foo"];
set => feature["foo"] = value;
}
/// <summary>
/// Gets or sets the API search results
/// </summary>
private IEnumerable<X> Results
{
get => (IEnumerable<X>)feature["searchResults"];
set => feature["searchResults"] = value;
}
public SearchSteps(FeatureContext feature)
{
this.feature = feature;
}
[When(@"I call POST /api/Search with")]
public void WhenICallPOST_api_searchWith(string json)
{
if (SearchId != null)
return;
var request = // parse json variable into object
SearchId = api.PostSearch(request);
}
[When(@"I call GET /api/Search")]
public void WhenICallGET_api_Search()
{
Results = api.GetSearch(SearchId);
}
[Then(@"The result size is (\d+)")]
public void ThenResultSizeIs(int expectedResultSize)
{
Assert.AreEqual(Results.Count(), expectedResultSize);
}
// Other 'Then' steps make assertions on Results property
}
您可以神奇地访问 FeatureContext,因为 SpecFlow 已经使用依赖注入框架注册了该对象。只需将 FeatureContext 参数添加到步骤定义的构造函数中即可访问此对象。
我发现在 FeatureContext
对象上创建 get/set 值的私有属性很好,所以你只在一个地方投射对象。此外,它还为事物提供了一个有意义的名称,并使您在步骤定义中更容易处理 FeatureContext。
您可以将 IEnumerable<X> Results
替换为对 GET /api/Search/:searchId
的响应类型的名称。