Strong coupling between steps in gherkin specifications

I use specflow to indicate my application and it just saved me from really bad stuff, so I really like it :-) However, I have a problem with the connection between the steps: For example, since I use mocks heavily in one step, I tell the layout. that it should return an entity, but in another I say mock to return the same object, but with a different property.

Take a look at this step (stolen from Darrens answer below and modified):

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

See here. I start with a Guy object and then modify the object - this is what I am testing.

So, I put the entity in the mock repository, then in another step I pull it out and paste it again. How do you avoid high linkage and reuse between stages?

Of course, I could save the local variable in the script class and put all the entities in this variable, but then I would take a couple of steps.

+3
source share
2 answers

The way I avoid binding and encouraging reuse is as follows:

1.) Group my actions with an object, for example, AccountRepositorySteps (for AccountRepository) or AccountControllerSteps (for AccountController).

2.) Take steps that depend on abstractions, not concrete (as with our production code).

3.) Rely on the current Context script to pass values ​​between steps and step files.

Here is a short example:

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 . - REAL- IRepository , , , ScenarioContext IRepository.

, , . , , SpecFlow, .

+6

, .

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

Source: https://habr.com/ru/post/1783598/


All Articles