1

この質問は、SpecFlow での値の共有に関する一般的な議論のためのものです。SpecFlow での経験に基づいて、建設的なフィードバックを提供してください。

私はこのテクノロジに比較的慣れていないため、ステップ定義ファイル間で値を共有するためのソリューションを探していたところScenarioContext.Current.Get、 とScenarioContext.Current.Set. これらは非常に便利ですが、私が見ているように、いくつかの問題があります。

  1. このアプローチには、非常に多くのタイピングが含まれます。
  2. 値の型は文字列インデックスで挿入および取得されるため、ステップ定義間の一貫性を確保するには、文字列定数または列挙型を使用する必要があります。
  3. 取得しようとしている値が挿入されていると想定するのは安全ではない可能性があります。

私は抽象化を思いついたので、これのいくつかを少し簡単に扱うことができると思いますが、人々がそれについてどう思うか疑問に思っています.

問題: 私の値は設定されていますか?

ScenarioContext.Currentこれに対する私の解決策は、シングルトン アクセサー クラスでラップすることでした。このクラスは のように動作しますが、値が見つからない場合にScenarioContext.Currentをスローする点が異なります。AssertInconclusiveException

    private static ScenarioContextAccessor instance;

    public static ScenarioContextAccessor Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new ScenarioContextAccessor();
            }

            return instance;
        }
    }

    private ScenarioContextAccessor() { }

    public T Retrieve<T>(string index)
    {
        try
        {
            T val = (T)ScenarioContext.Current[index];
            if (val == null)
            {
                throw new Exception();
            }

            return val;
        }
        catch
        {
            throw new AssertInconclusiveException(index + " of type " + typeof(T).Name + " was not found in the current scenario context. Did you execute your steps out of order?");
        }
    }

    public T Retrieve<T>()
    {
        try
        {
            T val = ScenarioContext.Current.Get<T>();
            if (val == null)
            {
                throw new Exception();
            }

            return val;
        }
        catch
        {
            throw new AssertInconclusiveException("No object of type " + typeof(T).Name+ " could be found in the current scenario context. Did you execute your steps out of order?");
        }
    }

    public void Set(string index, object value)
    {
        ScenarioContext.Current[index.ToLower(CultureInfo.InvariantCulture)] = value;
    }

    public void Set<T>(T value)
    {
        ScenarioContext.Current.Set<T>(value);
    }
}

問題: 入力が多すぎる!

これに対する私の解決策は、これらの値を必要とするステップ定義を作成して、 によってバックアップされるプライベート プロパティとして定義することScenarioContextAccessorです。値型にアクセスするすべてのプロパティは、文字列定数をインデックスとして使用します。

    private string FolderName
    {
        get
        {
            return ScenarioContextAccessor.Instance.Retrieve<string>(FolderingScenarioContextKey.FolderName);
        }
        set
        {
            ScenarioContextAccessor.Instance.Set(FolderingScenarioContextKey.FolderName, value);
        }
    }

    private UserDocumentMetadata Metadata
    {
        get
        {
            return ScenarioContextAccessor.Instance.Retrieve<UserDocumentMetadata>();
        }
        set
        {
            ScenarioContextAccessor.Instance.Set<UserDocumentMetadata>(value);
        }
    }

これで、単純なプロパティであるかのように、共有値に簡単にアクセスできるようになりました。

建設的なフィードバックがあればお寄せください。ありがとう!

4

2 に答える 2

0

パート1に関しては、私は同意しません。データが正しく設定されていない場合、テストを完全に失敗させる方が便利だと思います。

パート 2 に関しては、私はすでにこのようなパターンを使用しています。特に、テスト対象のオブジェクトのインスタンスを取得するために、多くの入力と潜在的なエラーを節約できるためです。

クラスのダミーインスタンスが必要な場合にパート1のソリューションの代わりに(状況に応じて)役立つ別のパターンは、遅延初期化アプローチです。

public static Mock<T> GetOrMockAndStore<T>() where T : class
    {
        Mock<T> output;
        if (ScenarioContext.Current.TryGetValue(out output))
        {
            return output;
        }
        else
        {
            output = new Mock<T>();
            ScenarioContext.Current.Set(output);
        }
        return card;
    }

私は Moq を使用しています - 非常に便利なフレームワークです。

于 2012-01-26T21:07:00.577 に答える
0

あなたが探している機能は Context Injection (依存性注入) だと思います: https://github.com/techtalk/SpecFlow/wiki/Context-Injection

これにより、ステップ定義間でクラスを共有できます。

于 2013-06-07T09:00:18.770 に答える