Reputation: 21809
TL;DR; How can I create a specflow test that calls another test as its first step?
Given I already have one specflow test
And I want to run another test that goes deeper than the first test
Then I create a second test that runs the first test as its first step
And I add additional steps to test the deeper functionality
Sorry, little bit of specflow humor there.
eg I have a test that creates a sale already:
Given I want to create a sales order
And I open the sales order page
And I click the add new order button
Then a new sales order is created
And I want to have another test that tests adding a sales line
And another test that tests completing the sale
And another test that cancels the sale
And .. so on
All of those tests would start with the same first four steps as the simple test, which breaks the DRY principle. So how can I do it so that the first step of the 2nd test just runs the first test? eg something like:
Given I have run the create sales order test // right here it just runs the first test
And I add a sales order line
Then the order total is updated
If every test starts off with the same first four lines, and later on I realize that I need to change the simple create sale test, then I will also need to go and find and fix everywhere else that repeats those four lines.
EDIT: Note that this should also be able to work across features. eg The simple test above is defined in the sales feature. But I would also have a credits feature, and that would require creating a sale each time in order to be able to credit it:
Given I want to credit a sale
And I run the create sales order test
And I complete the the sale
And I click the credit button
Then the sale is credited
Upvotes: 15
Views: 14791
Reputation: 298
If I understand the question correctly, you want to call other scenarios across different feature files.
or
Upvotes: -1
Reputation: 18783
You don't need to run actual steps to create a sales order. Just implement a step definition that does this for you as a one-liner.
First, the fictional SalesOrder
class:
public class SalesOrder
{
public double Amount { get; set; }
public string Description { get; set; }
}
Then the step definitions
using TechTalk.SpecFlow;
using TechTalk.SpecFlow.Assist;
[Binding]
public class SalesOrderSteps
{
[Given("I have already created a Sales Order")]
public void GivenIHaveAlreadyCreatedASalesOrder()
{
var order = new SalesOrder()
{
// .. set default properties
};
// Save to scenario context so subsequent steps can access it
ScenarioContext.Current.Set<SalesOrder>(order);
using (var db = new DatabaseContext())
{
db.SalesOrders.Add(order);
db.SaveChanges();
}
}
[Given("I have already created a Sales Order with the following attributes:")]
public void GivenIHaveAlreadyCreatedASalesOrderWithTheFollowingAttributes(Table table)
{
var order = table.CreateInstance<SalesOrder>();
// Save to scenario context so subsequent steps can access it
ScenarioContext.Current.Set<SalesOrder>(order);
using (var db = new DatabaseContext())
{
db.SalesOrders.Add(order);
db.SaveChanges();
}
}
}
Now you can create Sales orders as a one-liner and optionally include some custom attributes:
Scenario: Something
Given I have already created a Sales Order
Scenario: Something else
Given I have already created a Sales Order with the following attributes:
| Field | Value |
| Amount | 25.99 |
| Description | Just a test order |
If you need to access that SalesOrder
object in other step definitions without querying for it in the database, use ScenarioContext.Current.Get<SalesOrder>()
to retrieve that object from the scenario context.
Upvotes: 4
Reputation: 32936
As noted already you can use a background for this (and that's probably the best option in most situations), but you can also create a step which calls the other steps.
[Binding]
public class MySteps: Steps //Inheriting this base class is vital or the methods used below won't be available
{
[Given("I have created an order")]
public void CreateOrder()
{
Given("I want to create a sales order");
Given("I open the sales order page");
Given("I click the add new order button");
Then("a new sales order is created");
}
}
which you can then use in your scenario:
Scenario: I add another sale
Given I have created an order
When I add a sales order line
Then the order total is updated
This has the advantage that this composite step can be used anywhere in the scenario and not just as a starting point. This step can then be reused across multiple features if you need
Upvotes: 18
Reputation: 5445
Use a Background:
Background:
Given I want to create a sales order
And I open the sales order page
And I click the add new order button
Then a new sales order is created
Scenario: I add another sale
When I add a sales order line
Then the order total is updated
Scenario: I add cancel a sale
When I cancel a sale
Then the order total is updated to 0
etc.
Upvotes: 6