web-dev-qa-db-ja.com

Specflowと別の機能からのステップの再利用

私はスペックフローを学ぼうとしています。現在、2つの機能ファイルがあります。

2番目の機能ファイルでは、最初の機能ファイルのステップを再利用しています。

Specflowは最初の機能ファイルからのステップを自動的に認識し、specflowが2番目の機能のステップを生成したとき、それは賢く、再利用しているステップを再生成しませんでした。

ただし、このステップは指定されたステップであり、フィーチャクラスのメンバーフィールドを初期化します。

シナリオコンテキストを使用せずに、クラスのメンバーを初期化する別のフィーチャファイルのステップを再利用するにはどうすればよいですか?

編集

たとえば、Given Iがログインしている場合、それはいくつかの機能ファイルで使用されます。この「Given」は、ログに記録されるユーザーオブジェクトを作成し、それを.cs機能ファイルのメンバーとして保存します。

同じGivenを別の.featureで使用すると、Specflowは対応する.csファイルでそれを再生成しません。それを使用しているシナリオをデバッグすると、最初の.csファイルから実行されます。

しかし、最初の.cs機能ファイルのメンバーにアクセスできません。静的メンバーを使用することを計画していますが、おそらく別の解決策がありますか?

どうもありがとう。

13
user2846391

ここでの大きなポイントは、ステップBindingsがグローバルであるということです。これは、多くの人が経験するSpecflowの一般的なアンチパターンのようです。最初に、機能ファイルに一致するバインディングクラスの階層を作成するフェーズがあります。代わりに、機能と一致しないコラボレーションクラスを作成する必要がありますが、代わりにそれらのコラボレーションを通じて機能を生成します。

メインのアプリケーションコードと同じです。単一のATMMachineCashWithdrawalクラスはなく、代わりにATMMachinePINCodeCheck、およびOperationSelectionを持つWithdrawalOperationがあります。これらのオブジェクトは連携して「現金を引き出したい」機能を作成し、「残高の確認」機能を追加すると、WithdrawalOperation以外のすべてを再利用できます。

Specflowのバインディングは同じです。 ATMTesterを設定する方法を知っていてGiven I have a cash machine full of cashを提供するATMMachineがあり、Given my account has loads of money in itを使用してアカウントの残高を偽造/モック/設定する方法を知っているCustomerTesterがある場合があります。

幸い、SpecFlowはクラスを共同作業する方法も提供します。ご覧ください http://www.specflow.org/documentation/Sharing-Data-between-Bindings/

19
AlSki

私はちょうど同じ問題を抱えていました。派生クラスの属性「Binding」を設定し、各クラスのスコープを設定する必要があります。

2つの機能があるとしましょう:

  • 機能:私の最初の機能
  • 機能:私の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
{

}
7
DavideGalifi

私が行ったことの1つは、単一の大規模なpartial classさまざまな* .csファイルに分割します。

これにより、関連するものを独自のファイルに分離しておくことができますが、フィクスチャコードを再利用するための多くのオプションが提供されます。

例えば(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 ...
    }
}
0
Greg

2つの機能ファイルがあるとおっしゃっていましたが、シナリオで共通のステップを使用する2つのシナリオと、実装が異なる2つの同じ名前のステップで1つの機能ファイルを作成することも検討してください。 (オーバーロードされた関数)

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     |
    |[email protected]    | 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);
         }
0
Burak