TLDR - 什么是编写彼此后续的specFlow场景并共享数据的最佳方式?例如场景A - 创建用户,然后使用该用户登录场景B(登录将需要在创建用户场景中指定的用户名和密码)。
大家好,
我试图找出在网站上为典型的注册用户表单编写场景的最佳方法,然后是测试登录的场景,这让我有点蠢蠢欲动。
我尝试创建一个单独的类的实例来存储我的注册表单到达此步骤时的所有详细信息(认为这是上下文注入)。 e.g。
var data = [
{
"name": "bootstrap-table",
"stargazers_count": "526",
"forks_count": "122",
"description": "An extended Bootstrap table with radio, checkbox, sort, pagination, and other added features. (supports twitter bootstrap v2 and v3) "
},
{
"name": "multiple-select",
"stargazers_count": "288",
"forks_count": "150",
"description": "A jQuery plugin to select multiple elements with checkboxes :)"
},
{
"name": "bootstrap-show-password",
"stargazers_count": "32",
"forks_count": "11",
"description": "Show/hide password plugin for twitter bootstrap."
},
{
"name": "blog",
"stargazers_count": "13",
"forks_count": "4",
"description": "my blog"
},
{
"name": "scutech-redmine",
"stargazers_count": "6",
"forks_count": "3",
"description": "Redmine notification tools for chrome extension."
}
];
$(function () {
$('#table').bootstrapTable('load', {total: 5, rows: data});
checkedRows = [];
$('#table').on('check.bs.table', function (e, row) {
checkedRows.push({name: row.name, stargazers_count: row.stargazers_count, forks_count: row.forks_count, description: row.description});
console.log(checkedRows);
});
$('#table').on('uncheck.bs.table', function (e, row) {
$.each(checkedRows, function(index, value) {
if (value.name === row.name) {
checkedRows.splice(index,1);
}
});
console.log(checkedRows);
});
$('#getSelected').click(function() {
console.log(checkedRows);
})
});
我遇到的问题是以下场景需要在上一个场景中生成的密码,而我无法使用类似的内容访问它...
[Binding]
public class AdmissionsPortalFeaturesSteps : BaseStep
{
private UserDetails userDetails;
这就是我目前无法正常工作的内容,因为我想将密码值从第一个场景传递到第二个场景...(注意如果该字段设置为'随机',则会在我的内容中生成一个随机值c#代码)
userDetails.Password
目前我看到我有以下选项
或者其他我没想过的东西......
非常感谢,
答案 0 :(得分:3)
我尝试确保我的specflow场景不共享任何数据,并且如果我可以在每次测试之间显式重新生成整个数据库架构。
这确保只有您在测试中安排的数据才在数据库中
因此,我创建了一个单独的Given步骤,要么运行所有步骤来创建一个帐户(您可以以编程方式调用这些步骤),要么有一个单独的Given步骤,将所有使db需要的信息与数据一起短接的步骤
我还注意到您在测试中明确关闭了浏览器。我为启动/停止Selenium的Web创建了BeforeScenario / AfterScenario标记。因此,您的测试只需要测试实际功能,而不是测试Selenium的启动/停止。
public class SeleniumController
{
public static readonly SeleniumController Instance = new SeleniumController();
public static readonly TimeSpan DefaultTimeout = TimeSpan.FromSeconds(10);
public IWebDriver Selenium { get; private set; }
private void Trace(string message) { Console.WriteLine("-> {0}", message); }
public void Start()
{
if (Selenium != null)
return;
string appUrl = ConfigurationManager.AppSettings["AppUrl"];
var options = new ChromeOptions();
options.AddArgument("test-type");
Selenium = new ChromeDriver(options);
Selenium.Manage().Timeouts().ImplicitlyWait(DefaultTimeout);
Trace("Selenium started");
}
public void Stop()
{
if (Selenium == null) return;
try
{
Selenium.Quit();
Selenium.Dispose();
}
catch (Exception ex)
{
Debug.WriteLine(ex, "Selenium stop error");
}
Selenium = null;
Trace("Selenium stopped");
}
}
方案标签
public static class SeleniumSupport
{
private static bool ReuseWebSession
{
get { return ConfigurationManager.AppSettings["ReuseWebSession"] == "true"; }
}
[BeforeScenario("web")]
public static void BeforeWebScenario()
{
SeleniumController.Instance.Start();
}
[AfterScenario("web")]
public static void AfterWebScenario()
{
if (!ReuseWebSession)
SeleniumController.Instance.Stop();
}
}
抽象步骤基类访问selenium webdriver
public abstract class SeleniumStepsBase
{
protected IWebDriver Selenium { get { return SeleniumController.Instance.Selenium; } }
}
答案 1 :(得分:2)
您打算使用一个场景为另一个场景设置数据是有缺陷的,注定要失败恕我直言。
场景应该完全自包含,并且能够独立运行,而不依赖于其他场景。 Specflow是一个单元测试生成框架,但测试运行器可以决定运行测试的顺序。如果你有一个你想要的依赖,那么如果他们不按顺序运行会发生什么?如果它们并行运行会发生什么?试图做这项工作将向上游游泳,不要这样做。
而是使每个场景自包含。如果你有很多重复的设置,把它放在后台步骤,或者创建一个调用所有其他步骤进行设置的步骤,或者只是创建一个只进行所需设置的步骤,然后使用标准方法在步骤之间共享数据以管理生成的密码等等。
答案 2 :(得分:0)
我使用FeatureContext.Current或ScenarioContext.Current来存储我在场景或功能之间传递的信息。 FeatureContext是一个Specflow全局字典,可以在任何地方访问。 Specflow FeatureContext
FeatureContext.Current["username"] = "someUsername";
或者
ScenarioContext.Current["username"] = "someUsername";