2011-01-05 4 views
3

私のアプリケーションを指定するためにspecflowを使用しています。本当に悪いものから私を救ったので、私は本当に好きです:-) しかし、私はステップ間のカップリングに問題があります: 例えば、私はモックを1ステップで大量に使用しているので、モックにエンティティを返すように指示しますが、別のものでは、同じエンティティを返すようにモックに指示しますが、別のプロパティを返します。小枝仕様のステップ間の強い結合

このステップを見(Darrensから盗まれたが、以下の答え、修正):

Given a guy the following guy exists: 
| Name  | Age | Salary | 
| John Doe | 42 | 400 | 
When his salary changes to 420 
And I run the paycheck program 
Then he should be paid 420 

は、私はガイオブジェクトで始まり、後にオブジェクト変更ここを参照してください - 私がテストしていものです。

私はモックリポジトリにエンティティを入れて、別のステップでそれを取り出してもう一度入れます。 ステップ間の高い結合と再利用を避けるにはどうすればよいですか?

もちろん、シナリオクラスにローカル変数を保存して、その変数にすべてのエンティティを入れることができますが、手順を結合します。 )AccountRepository用AccountRepositorySteps()またはAccountControllerStepsのような(AccountControllerのために、エンティティによって

1)グループの私のステップ:私はカップリングを回避し、再利用性を促進

答えて

6

方法がにあります。

2.)ステップはコンクリートではなく、抽象化に依存します(プロダクションコードと同じように)。

3.現在のScenarioContextを参照して、ステップとステップファイルの間で値を渡します。

ここでは簡単な例です:

Given a guy with the name Darren exists 
And a guy with the name John exists 
When I hit the guy page 
Then I should see two guys 

RepositorySteps.cs

private List<string> guys; 

[BeforeScenario] 
public void Setup(){ 

    guys = new List<string>(); 

    var fake = new Mock<IRepository>(); 

    fake.Setup(x=>x.GetGuys()).Returns(guys); 

    ScenarioContext.Current.Set(fake) // Mock<IRepository> 
    ScenarioContext.Current.Set(fake.Object); // IRepository 
} 

[Given("a guy with the name '(.*)' exists"] 
public void a(string guy){ 
    guys.Add(guy); 

    // and if I need to pull out the mock, I can do it like so 
    var fake = ScenarioContext.Current.Get<Mock<IRepository>>(); 
} 

GuyController.cs

When["I hit the guy page"] 
public void x(){ 
    var repository = ScenarioContext.Current.Get<IRepository>(); 
    var controller = new GuyController(repository); 

    var result = controller.Index(); 
    ScenarioContext.Current.Set(result); 
} 

を参照してください、ここでGuyControllerためのステップは、そのモックオブジェクトを取得しますが、彼はそれが偽であることを知らない。彼はただのIRepositoryです。何らかの理由でIRepository用のREALリポジトリをロードしてスペックを実行する必要がある場合は、実際のIRepositoryでScenarioContextをロードするだけです。

このパターンに従えば、私のステップは非常に切り離され、他の人が行った変更から保護されます。私がSpecFlowを使用した初期のトリックよりも優れています。静的メソッドを使用したり、無関係なステップを同じステップファイルでグループ化したりします。

0

振る舞いを分けるほうがいいのだろうかと思います。

Scenario: Change Salary 

Given a guy the following guy exists: 
| Name  | Age | Salary | 
| John Doe | 42 | 400 | 
When his salary changes to 420 
Then his salary should be 420 

そして...

Scenario: Pay Guy 

Given a guy the following guy exists: 
| Name  | Age | Salary | 
| John Doe | 42 | 400 | 
And I run the paycheck program 
Then he should be paid 400 

彼らは行動の独立したユニットです。

共有コンテキストに関しては、私が一番きちんとした解決策は依存性注入です。いくつかのSharedContextクラスを作成し、それを共有コンテキストが必要なステップ定義クラスに挿入します。そうすることで、ステップ定義ファイルを分割して、必要に応じて分割して、コンテキストを共有することができます。多くのツールには、簡単なIoCコンテナの機能(例えばSpecFlow)が付属しています。

class SharedContext 
{ 
object MyObject1 {get; set;} 
object MyObject2 {get; set;} 
//Etc. 
} 

class StepDefinitions1 
{ 

private SharedContext _context; 

public Stepdefinitions1(SharedContext context) 
{ 
this._context = context; 
}  
//Now use this._context.Properties to get at the shared objects in your 
//step definitions  
} 

容器は残りの部分を処理します。

SharedContextクラスのオブジェクトライフサイクルは、単一のシナリオです。私。新しいシナリオごとに、新しいSharedContextが作成され、最後の「Then」ステップが実行されるまで、それを参照するクラスのすべてのステップにコンストラクタを介して渡されます。

+0

おっと!古い投稿。 –