I'm trying to create a new set of tests for testing a legacy web site that I'm working on. The site uses a database at the back end. I'm planning on using SpecFlow and Selenium, however I'm a bit stumped on what the best way to deal with cleaning up data is.
Currently I have a database backup with a set of sample data which I restore before each test run. This however is cumbersome so I would like to only do this for critical test runs before a release and leave the continuous integration runs working on the same database in between.
Currently I have a large number of tests that go something like this:
Secenario: Test Item Creation
Given I am logged in
When I create an item with a unique name
Then an item exists with the unique name
The when step uses a GUID to ensure the name is unique and the then step has access to this via a module variable to check that it exists.
Like I said however I have a lot of tests similar to this and I'm running them multiple times on the same database so the test system is getting stuffed full of items which is slowing down searches and the like.
My question is what is the best way to deal with this? Should I create another step in the test that deletes the item again like this:
Secenario: Test Item Creation
Given I am logged in
When I create an item with a unique name
Then an item exists with the unique name
Then delete the item with the unique name
Or should my test framework somehow be able to deal with this? If so what do people do? Given SpecFlow step's global nature I'd imagine that getting the teardown steps in the correct order if multiple items with parent-child relationships could become problematic.
Just like with normal unit tests, you can also ignore SpecFlow tests. To do so, tag the feature or scenario with the @ignore tag.
Example keyword can only be used with the Scenario Outline Keyword. Scenario Outline - This is used to run the same scenario for 2 or more different sets of test data. E.g. In our scenario, if you want to register another user you can data drive the same scenario twice.
Hooks (event bindings) can be used to perform additional automation logic at specific times, such as any setup required prior to executing a scenario. In order to use hooks, you need to add the Binding attribute to your class: [Binding] public class MyClass { ... }
Since SpecFlow 3.1 you can do skip programmatically Scenarios with the UnitTestRuntimeProvider. Ignoring is like skipping the scenario. Be careful, as it behaves a little bit different for the different unit test runners (xUnit, NUnit, MSTest, SpecFlow+ Runner).
As we saw in the last article, Specflow does provide a mechanism to auto-generate the Step definitions (which can later be customized/modified as required). Navigate to the feature file, Right-click and select “Generate Step Definitions”.
There are several ways of implementing higher-level steps. One common, but mistaken approach, would be to just call lower-level steps from higher-level steps. SpecFlow does support such calls, allowing us to to implement the sharing just below the feature file layer, in the step implementations.
Hooks are a feature of Specflow, and most other Given/When/Then tools, allowing developers to specify actions to execute before or after a feature, a scenario or even individual steps. In the previous examples, the specific user wasn’t that important.
A good test should have no dependencies, so having test steps create and then "tear down" test data is a good idea.
One approach you could take is to store the unique name generated by:
When I create an item with a unique name
in the ScenarioContext object e.g.
ScenarioContext.Current["testItem"] = "testItemName";
This will allow you to persist this value for the duration of the scenario.
You could then create a SpecFlow hook associated with a specific tag to tear-down this data when the scenario completes e.g. The scenario would be (note the tag):
@deleteTestItem
Secenario: Test Item Creation
Given I am logged in
When I create an item with a unique name
Then an item has exists with the unique name
And the code to clean up would be:
[AfterScenario("deleteTestItem")]
public void DeleteTestItem()
{
var testItemName = ScenarioContext.Current["testItemName"];
// Use testItemName to clean-up your database
}
This code will then only be run for scenarios which have this tag. Note that if all your tests involved creating a test item, then you could omit the tag and simply use an AfterScenario hook.
Alternatively you could persist all of the test item names in the FeatureContext, and then delete these items in an AfterFeature hook. This would lead to less database calls (i.e. you would not be calling the database to clean-up after every scenario).
I prefer the ScenarioContext approach as I feel that if a Scenario creates data, then that scenario should be responsible for cleaning-up after itself.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With