2011-01-05 76 views
3

我使用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 

看到这里我开始和一个男生对象,后来修改的对象 - 这是我测试的东西。

因此,我把一个实体放到模拟库中,然后在另一个步骤中将其拉出并重新放入。 如何避免步骤之间的高耦合和可重用性?

当然,我可以在场景类中保留一个局部变量,并将所有实体放在该变量中,但是然后我会耦合这些步骤。

回答

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存储库并想运行您的规格,那么您只需将ScenarioContext加载到真正的IRepository中即可。

按照这种模式,我的步骤是非常脱钩,并保护我免受其他人的变化。它比我在使用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

哎呀!旧帖子。 – 2012-09-27 11:17:48