1

私は SpecFlow を初めて試していますが、コンセプト全体を考えすぎているのか、それとももっと悪いことに、本来の目的のために完全に誤用しているのかを知りたいですか?

私は自分の WinForms プロジェクトに MVP-VM アーキテクチャ デザイン パターンを採用し、同じパターンに従う将来のプロジェクトを定義するボイラープレート ストーリーを設定しようと考えました。

どんな提案でも大歓迎です、ありがとう!

Feature: DesignPattern
    In order to encourage pluggability and loose coupling
    As a software developer who has to comply with company GUI standards
    I want to make sure the MVP-VM design pattern is enforced

@mytag
Scenario: MainPresenter loosely couples with IMainView and IModelContainer implementations
    Given a stub of the IMainView interface
    And a stub of the IModelContainer interface
    When I create a new MainPresenter with the IMainView and IModelContainer stubs as arguments
    Then the MainPresenter should have the IMainView and IModelContainer stubs as properties

Scenario: MainPresenter tightly couples with MainViewModel
    Given a stub of the IMainView interface
    And a stub of the IModelContainer interface
    When I create a new MainPresenter with the IMainView and IModelContainer stubs as arguments
    Then the MainPresenter should have a collection of MainViewModels as a property

Scenario: IModelContainer contains all required model interfaces
    Given a stub of the IModelContainer interface
    Then the IModelContainer stub should have an IContractsModel property

Scenario: IMainView extends the company BaseView GUI standard
    Given a stub of the IMainView interface
    Then the IMainView stub should extend the IBaseView interface

Scenario: IMainView exposes a datasource binding method that accepts a collection of MainViewModels as argument
    Given a stub of the IMainView interface
    And a collection of MainViewModels
    Then the IMainView stub should have a BindViewModelsList method that accepts the collection of MainViewModels

Scenario: MainViewModel takes a ContractDataEntity and stores it as a property
    Given a ContractDataEntity
    When I create a new MainViewModel with the ContractDataEntity as argument
    Then the MainViewModel should have the ContractDataEntity as a property

Scenario: MainViewModel presents the required attributes of its associated DataEntity
    Given a ContractDataEntity
    When I create a new MainViewModel with the ContractDataEntity as argument
    Then the MainViewModel should have the ContractDataEntity ContractNumber as a property
    And the MainViewModel should have the ContractDataEntity CustomerCode as a property

Scenario: MainViewModel has a factory method that translates a collection of DataEntities into MainViewModels
    Given a collection of ContractDataEntities
    When I call the MainViewModel TranslateDataEntityList factory method
    Then it should return a collection on MainViewModels

次に、SpecFlow メソッドからクラス、プロパティ、およびメソッド スタブを生成します。

using Rhino.Mocks;
using Should.Fluent;
using TechTalk.SpecFlow;

namespace CONTR001.Test
{
    [Binding]
    public class DesignPatternSteps
    {
        [Given(@"a stub of the IMainView interface")]
        public void GivenAStubOfTheIMainViewInterface()
        {
            IMainView view = MockRepository.GenerateStub<IMainView>();
            ScenarioContext.Current.Set(view);
        }

        [Given(@"a stub of the IModelContainer interface")]
        public void GivenAStubOfTheIModelContainerInterface()
        {
            IModelContainer model = MockRepository.GenerateStub<IModelContainer>();
            ScenarioContext.Current.Set(model);
        }

...

        [When(@"I create a new MainPresenter with the IMainView and IModelContainer stubs as arguments")]
        public void WhenICreateANewMainPresenterWithTheIMainViewAndIModelContainerStubsAsArguments()
        {
            var view = ScenarioContext.Current.Get<IMainView>();
            var model = ScenarioContext.Current.Get<IModelContainer>();
            var presenter = new MainPresenter(view, model);
            ScenarioContext.Current.Set(presenter);
        }

...

        [Then(@"the MainPresenter should have the IMainView and IModelContainer stubs as properties")]
        public void ThenTheMainPresenterShouldHaveTheIMainViewAndIModelContainerStubsAsProperties()
        {
            var presenter = ScenarioContext.Current.Get<MainPresenter>();
            presenter.View.Should().Equal(ScenarioContext.Current.Get<IMainView>());
            presenter.Model.Should().Equal(ScenarioContext.Current.Get<IModelContainer>());
        }

...

        [Then(@"the IMainView stub should extend the IBaseView interface")]
        public void ThenTheIMainViewStubShouldExtendTheIBaseViewInterface()
        {
            var view = ScenarioContext.Current.Get<IMainView>();
            view.Should().Be.AssignableFrom<IBaseView>();
        }
    }
}
4

2 に答える 2

2

考えすぎ/意図した目的で使用していないことに疑問を持っているという事実は、この経験からすでに多くのことを学んでいることを示しています. SpecFlow は、ビジネスから知識を取得し、成功の基準を定義するプロセスである BDD をサポートするために主に使用されるツールです。これは間違いなく BDD ではありませんが、これらのテストを導出することで、ドメインを詳細に検討できるようになったことは確かに想像できます。仕様を介して単体テストの完全な例をいくつか生成しました。これは役に立ちます。コードベースが十分に成熟して目的を果たせなくなったと判断したら、将来 (まだ) これらのテストを削除することを選択する可能性があります。

初めて SpecFlow を使い始めたとき、これらと非常に似たレベルの粒度で多数のテストを作成しました。また、システム統合レベルに近い、はるかに高いレベルでさらにいくつかのことを書きました。後から考えると、私の意見は変わり、nUnit で同じような低レベルのテストを書き、SpecFlow で高レベルのテストを書いていることに気付きました。それぞれの手法にはそれぞれの役割があり、Specflow から c# Bindings への変換により、低レベルのテストの複雑さがさらに増したことがわかりました。

ただし、SpecFlow/Gherkin/BDD をあきらめないでください。適切なレベルの粒度で使用すると、単体テストよりも優れた利点がいくつかあります。満足できるレベルを見つけるだけです。私にとって、それは機能ファイルを引き出して、コーヒーを飲みながら誰かと話し合うことができる場所です.

于 2013-03-04T13:48:59.053 に答える
1

私が理解している本来の目的で SpecFlow を使用しているとは思いませんが、まだ「理解」しており、行ったことはまだ有効に使用されていると思います。

私が理解しているように、SpecFlow は動作を記述するためのものであり、それらのシナリオが動作そのものであるとは言えません。ただし、適切な言語で要件を記述し、それらのテストを作成することができたので、その点でも有用であることが証明されていると思います. 頑張って!

于 2013-03-04T13:00:34.093 に答える