カップリングを避けて再利用性を促進する方法は次のとおりです。
1.) AccountRepositorySteps (AccountRepository の場合) または AccountControllerSteps (AccountController の場合) のように、ステップをエンティティ別にグループ化します。
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 リポジトリをロードする必要があり、spec を実行したい場合は、ScenarioContext に実際の IRepository をロードするだけです。
このパターンに従って、私のステップは非常に分離され、他の人に加えた変更から保護されます。これは、静的メソッドを使用したり、無関係なステップを同じステップ ファイルにグループ化したりする、SpecFlow を使用する初期の頃に行ったトリックよりもはるかにうまく機能します。