我正在使用specflow来指定我的应用程序,它只是让我免于做坏事,所以我真的很喜欢它:-) 但是我对步骤之间的耦合有问题: 例如,因为我在一步中大量使用模拟,我告诉模拟它应该返回一个实体,但在另一个中我告诉模拟返回相同的实体,但是使用另一个属性。
看看这一步(从以下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
看到这里我从一个Guy对象开始,然后修改对象 - 这是我正在测试的东西。
所以我将一个实体放入模拟存储库,然后在另一个步骤中将其拉出并再次放入。 如何避免步骤之间的高耦合和可重用性?
当然,我可以在方案类中保留一个局部变量,并将所有实体放在该变量中,但我会将这些步骤结合起来。
答案 0 :(得分:6)
我避免耦合和促进可重用性的方式是:
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存储库并想要运行您的规范,那么您所要做的就是使用真实的IRepository加载ScenarioContext。
遵循这种模式,我的步骤非常分离,并且不受我对其他人所做的更改的影响。它比我在使用SpecFlow时做的技巧要好得多,我在同一步骤文件中使用静态方法或组合无关的步骤。
答案 1 :(得分: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”步骤。