我正在尝试学习specflow,现在。 目前我有2个功能文件。
在第二个功能文件中,我正在重复使用第一个功能文件中的步骤。
Specflow会自动识别第一个功能文件中的步骤,当specflow为我的第二个功能生成步骤时,它很聪明,并且没有重新生成我重复使用的步骤。
但是这一步是一个Given步骤,它初始化了要素类的成员字段。
不使用场景上下文,如何重用初始化类成员的其他功能文件中的步骤?
例如,如果您有一个已登录的,则会在多个功能文件中使用。 这个“Given”创建一个用户对象,该用户对象被记录并将其存储为.cs特征文件中的成员。
当您在另一个.feature中使用相同的Given时,Specflow不会在相应的.cs文件中重新生成它。当您调试正在使用它的场景时,它会从第一个.cs文件执行它。
但我无法访问第一个.cs功能文件的成员。我打算使用静态成员,但也许有另一种解决方案?
非常感谢。
答案 0 :(得分:17)
这里的重点是步骤Binding
是全局的。
这似乎是许多人经历的Specflow的常见反模式。最初,您有一个阶段,即创建与您的要素文件匹配的绑定类的层次结构。相反,您需要创建与功能不匹配的协作类,而是通过协作生成功能。
就像你的主要应用程序代码一样。您不会有一个ATMMachineCashWithdrawal
课程,而是拥有ATMMachine
,PINCodeCheck
,OperationSelection
和WithdrawalOperation
。这些对象协作使您的“我想提取现金”功能,当您添加“检查我的余额”功能时,您可以重用除WithdrawalOperation
之外的所有内容。
Specflow中的绑定是相同的。我们可能有一个ATMTester
知道如何设置ATMMachine
并提供您的Given I have a cash machine full of cash
,并且您可以拥有CustomerTester
知道如何伪造/模拟/设置您的帐户余额与Given my account has loads of money in it
。
幸运的是,SpecFlow也提供了协作类的方法。看看http://www.specflow.org/documentation/Sharing-Data-between-Bindings/
答案 1 :(得分:4)
我遇到了同样的问题。你需要设置属性" Binding"对于派生类,并为每个类设置范围。
我们假设您有2个功能:
功能:我的第二个功能
Feature: My First Feature
Background:
Given a precondition
When ...
Then ...
Feature: My Second Feature
Background:
Given a precondition
When ...
Then ...
你有一个BaseClass定义共享行为
// no Binding attribute for the BaseClass
public class BaseClass
{
[Given(@"a precondition")]
public void GivenAPrecondition()
{
}
}
然后定义2个功能的行为的2个类
[Binding]
[Scope(Feature = "My First Feature")]
public class MyFirstFeature : BaseClass
{
}
[Binding]
[Scope(Feature = "My Second Feature")]
public class MySecondFeature : BaseClass
{
}
答案 2 :(得分:0)
我做过的一件事是在各种* .cs文件之间使用单个大量partial class
分割。
这使您可以将相关内容保存在自己的文件中,但仍然可以为重复使用灯具代码提供大量选项。
e.g。 (Feature1Steps.cs)
namespace YourProject.Specs
{
[Binding] // This can only be used once.
public partial class YourProjectSpecSteps
{
// Feature 1 methods ...
}
}
并为下一个功能 (Feature2Steps.cs)
namespace YourProject.Specs
{
public partial class YourProjectSpecSteps // same class, already bound
{
// Feature 2 methods ...
}
}
答案 3 :(得分:0)
我知道您提到过您有两个功能文件,但您可能还想考虑创建一个功能文件,其中包含两个场景,其中场景使用公共步骤以及两个具有不同实现的相同命名步骤。 (重载函数)
Ex: Login.featue file
Feature: Login
Test the login functionality of the application.
Will verify if the username and password combination is working as expected.
Scenario: Verify if the login functionality is working
Given I have navigated to the application
# user name and password are hard coded
When I fill in my form
| username | password |
|name@xyz.com | pwd |
....
Scenario: Verify if the login functionality is working for sql server data
Given I have navigated to the application
# gets the user name and password from the database
When I fill in my form
....
LoginSteps.cs file
[Binding]
public class LoginSteps
{
[Given(@"I have navigated to the application")]
public void GivenIHaveNavigatedToTheApplication()
{
// this code is used by both scenarios
Browser.Navigate().GoToUrl(ConfigurationManager.AppSettings["TestUrl"]);
}
// hard coded username and password
[When(@"I fill in my form")]
public void WhenIFillInMyForm(Table table)
{
dynamic credentials = table.CreateDynamicInstance();
LoginFunction(credentials.username, credentials.password);
}
// gets the username and password from the database
[When(@"I fill in my form")]
public void WhenIFillInMyForm()
{
string username = "";
string password = "";
string sql = <select statement>;
using (SqlConnection connection = new SqlConnection())
{
connection.ConnectionString = ConfigurationManager.ConnectionStrings["SQLProvider"].ConnectionString;
connection.Open();
SqlCommand myCommand = new SqlCommand(sql, connection);
using (SqlDataReader myDataReader = myCommand.ExecuteReader())
{
while (myDataReader.Read())
{
username = myDataReader["name"].ToString();
password = myDataReader["pwd"].ToString();
}
}
}
LoginFunction(username, password);
}