Aimee Jones
Aimee Jones

Reputation: 911

Correct way to implement Background steps in SpecFlow

I am learning to use SpecFlow at the moment, and want to write a Feature which will include the tests to register a user.

I have the first test case, Register a Valid User. This will involve entering the username, and email, a password and a confirmation password. Click submit and the user should be registered and added to a DB.

My next test case would be an invalid case where I would do the above steps and then try to register a user with the same username, which should return an error. From what I can understand from examples I have found, I can use "Background" in my .feature file to specify steps that I want to execute before each scenario in the .feature file. This would involve creating a step in the Background section to register the user and calling the methods that were created in the Valid Register User case. This question has helped me a bit but also raised more questions for me as I cannot understand the proper usage of the tags and hooks available.

My questions are:

  1. Should the valid test case be in the same file as the rest of the scenarios? If the Background section is called for every scenario in that feature file then it would cause the valid test to fail (as it is essentially the valid test case)
  2. Is this the right way to go about structuring my tests? I have read about the SpecFlow hooks that can be used [BeforeScenario]/[AfterScenario] etc. but I'm not sure when these should be considered over the Background tag.
  3. I feel like there is a lot of duplication that could be avoided, for example just referencing the valid test case as a step in another test, rather than creating a step for it as well as a test case, but maybe this is how SpecFlow is supposed to work, is it?

So far for this test case I have the following in my .feature file.

    Feature: RegisterUser
    In order to register a user successfully
    A valid username, email, password (and confirmation password) must be entered


@register
Scenario: Valid Register User
    Given I have entered a username "testing", an email "[email protected]", a password "123456" and a confirmation password "123456"
    When I press submit
    Then the response code should be 200
    And the user should be added to the database with verfied set to False

Background: 
    Given I have registered a user "testing", "[email protected]", "123456" and "123456"

@register
Scenario: Username Already Taken
    Given I have entered a username "testing", an email "[email protected]", a password "123456" and a confirmation password "123456"
    When I press submit
    Then the response code should be 400

And my steps file is something like this:

using NUnit.Framework;
using System;
using System.Net.Http;
using TechTalk.SpecFlow;

namespace Tests.Specs
{
[Binding]
public class RegisterUserSteps
{
    private RegisterUserModel userInfo = new RegisterUserModel();
    private RegisterUserController user = new RegisterUserController()
    {
        Request = new HttpRequestMessage(),
        Configuration = new System.Web.Http.HttpConfiguration()
    };
    private ApiResponse response = new ApiResponse();
    private static string userTableName = "usersTable";
    private static string userTablePartitionKey = "USER_INFO";
    private static string userTableRowKey = "[email protected]";


    [Given(@"I have entered a username ""(.*)"", an email ""(.*)"", a password ""(.*)"" and a confirmation password ""(.*)""")]
    public void GivenIHaveEnteredAUsernameAnEmailAPasswordAndAConfirmationPassword(string p0, string p1, string p2, string p3)
    {
        userInfo.Username = p0;
        userInfo.Email = p1;
        userInfo.Password = p2;
        userInfo.ConfirmPassword = p3;
    }

    [When(@"I press submit")]
    public void WhenIPressSubmit()
    {
        response = user.Register(userInfo);
    }

    [Then(@"the response code should be (.*)")]
    public void ThenTheResponseCodeShouldBe(int p0)
    {
        Assert.AreEqual(p0, response.Status);
    }


    [Then(@"the user should be added to the database with verfied set to False")]
    public void ThenTheUserShouldBeAddedToTheDatabaseWithVerfiedSetToFalse()
    {
        UserEntity user = AzureUtilities.RetrieveEntity<UserEntity>(userTableName, userTablePartitionKey, userTableRowKey);
        Assert.IsNotNull(user);
        Assert.AreEqual(userInfo.Username, user.Username);
        Assert.AreEqual(userInfo.Email, user.RowKey);
        Assert.IsFalse(user.Verified);
    }

    [Given(@"I have registered a user ""(.*)"", ""(.*)"", ""(.*)"" and ""(.*)""")]
    public void GivenIHaveRegisteredAUserAnd(string p0, string p1, string p2, string p3)
    {
        //Using methods here that have been defined in previous steps
        GivenIHaveEnteredAUsernameAnEmailAPasswordAndAConfirmationPassword(p0, p1, p2, p3);
        WhenIPressSubmit();
        ThenTheResponseCodeShouldBe(200);
    }

Upvotes: 2

Views: 6172

Answers (1)

Fran
Fran

Reputation: 6520

I think that your are trying to jump to using background without actually having things that are common across your scenarios.

SpecFlow is pretty robust in that your can reuse a lot of steps if you just create a consistent structure to your steps.

Let's start with your feature. This feature reads like a developer script. Features are supposed to represent some business goal. Bear with my because I don't know what any of your business goals are

Feature: Register New Users
    In order to perform task that only registered users can do
    As a web site user
    I want to register for the site

Now that we know why we are writing code we can start laying out scenarios to achieve this.

Given I am not registered for the site
And I have filled out the registration form as follows
| Field                 | Value             |
| username              | testing           |
| email                 | [email protected] |
| password              | 123456            |
| password confirmation | 123456            |
When I submit the registration
Then the response code should be '200'
And the database should have an unverified user

This creates a number of sstepscenarios, but you are going to get immediate reuse because you are now passing in your variables for filling out a registration form, and checking the response code.

So now your username already taken scenario can change to

Scenario: Username taken
Given a user has registered with the following information
| Field                 | Value             |
| username              | testing           |
| email                 | [email protected] |
| password              | 123456            |
| password confirmation | 123456            |
And I have filled out the registration form as follows
| Field                 | Value             |
| username              | testing           |
| email                 | [email protected] |
| password              | 123456            |
| password confirmation | 123456            |
When I submit the registration
Then the response code should be '400'

So now the only step you need to implement is the first step

Given a user has registered with the following information

and since steps are just code, you can call your already defined steps from your first scenario like this

    [Given(@"a user has registered with the following information")]
    public void GivenAUserHasRegisteredWithTheFollowingInformation(Table table)
    {
        GivenIHaveFilledOutTheRegistrationFormAsFollows(table);
        WhenISubmitTheRegistration();
        ThenTheResponseCodeShouldBe(200)
    }

As for Hooks, I use these for more technical things. I do a lot of outside in testing that uses Selenium. I create a hook @web that runs before the scenario to spin up Selenium and tear it down after the scenario is complete. I've done the same with API testing in that maybe you want to spin up an HttpClient before the scenario and tear is down afterward. You can also do things like clearing a database or clearing and seeding to a known state before you actually start testing.

I hope this answers all of your questions.

Upvotes: 1

Related Questions