Question

I am learning SpecFlow and am doing a simple Com-Sci standard FizzBuzz project. Given a range of numbers Replace divisible by 3 with Fizz Replace divisible by 5 with Buzz Replace divisible by 3 and five with FizzBuzz.

this is a very simple application but it did raise a question for me. How to you write features to test multiple requiremts where they are all fired from one method call on an API? E.g. The API call would be as follows FizzBuzz.Replace(1, 100); with the Replace method code

public static string Replace (int min, int max)
{
       if (IsDiv3 && IsDiv5) {...}
       if (IsDiv3) {...}
       if (IsDiv5) {...}
       ...
}

My features in SpecFlow are as follows:

Feature: FizzBuzz
    In order to display Fizz Buzz in       range of numbers
    As a user I want to be able to see Fizz Buzz replace certain numbers

Scenario: Replace muliples of three and five with Fizz, Buzz or FizzBuzz
    Given I have a range of numbers from 1 to 15
    When I press Submit
    Then the result should be
    | Numbers   |
    |   1   |
    |   2   |
    |   Fizz    |
    |   4   |
    |   Buzz    |
    |   Fizz    |
    |   7   |
    |   8       |
    |   Fizz    |
    |   Buzz    |
    |   11      |
    |   Fizz    |
    |   13      |
    |   14  |
    |   FizzBuzz|

A further question is how to make the feature more meaningful if I do need to clump all the requirements in one feature.

Edit I am struggling to create multiple scenarios because as soon as i create a second one the first one fails.

scenario 1: replace divisable by 3 with Fizz
Expected = 1 2 Fizz 4 5 Fizz 7 8 Fizz 10 11 Fizz 13 14 Fizz
Actual =   1 2 Fizz 4 5 Fizz 7 8 Fizz 10 11 Fizz 13 14 Fizz (First test)
Actual =   1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 Fizz (Second test)

then do next scenario

Scenario 2: replace divisable by 5 with Buzz
Expected = 1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 Fizz
Actual =   1 2 Fizz 4 Buzz Fizz 7 8 Fizz Buzz 11 Fizz 13 14 Fizz (Second test)

The second scenario passes but the first one now fails. I wouldnt think opening up the API to do scenario 1, 2, 3 would be a good design for the app.

Thanks,

Was it helpful?

Solution

Saw your message on the mailing list. If you want to split up the test of Fizz, Buzz and FizzBuzz you could change your spec to create a scenario for each branch of your implementation (i.e. each "if"):

Scenario: Replace multiples of three with Fizz
    Given I have a range of numbers from 1 to 4
    When I press Submit
    Then the result should be
    | Numbers    |
    |   1        |
    |   2        |
    |   Fizz     |
    |   4        |

Scenario: Replace multiples of five with Buzz
    Given I have a range of numbers from 4 to 5
    When I press Submit
    Then the result should be
    | Numbers    |
    |   4        |
    |   Buzz     |

Scenario: Replace multiples of three and five with FizzBuzz
    Given I have a range of numbers from 14 to 16
    When I press Submit
    Then the result should be
    | Numbers    |
    |   14       |
    |   FizzBuzz |
    |   16       |

Another observation in your example is that your expectations are expressed in a table (essentially an array) but your results are expressed in a string. Since you're using SpecFlow to do API testing in this example, I would try to align those two more closely by either changing the spec or your API.

For example, consider the following API change "public static string[] Replace(int min, int max)". Your steps would then be easier to write - something like this:

[Binding]
public class FizzBuzzSteps
{
    private int _min;
    private int _max;
    private string[] _results;

    [Given(@"I have a range of numbers from (\d+) to (\d+)")]
    public void GivenIHaveARangeOfNumbers(int min, int max)
    {
        _min = min;
        _max = max;
    }

    [When(@"I press Submit")]
    public void WhenIPressSubmit()
    {
        _results = FizzBuzz.Replace(_min, _max);
    }

    [Then(@"the result should be")]
    public void ThenTheResultShouldBe(Table table)
    {
        for (var i = 0; i < table.RowCount; i++)
        {
            var expected = table.Rows[i]["Numbers"];
            var actual = _results[i];
            Assert.AreEqual(expected, actual);
        }
    }
}

HTH, Dan Mork

OTHER TIPS

When you run the Specification you showed, specflow will suggest you create a method like this:

[Then(@"the result should be")]
    public void ThenTheResultShouldBe(Table table)

You can iterate and retrieve the values from your table like this:

[Then(@"the result should be")]
    public void ThenTheResultShouldBe(Table table)
    {
        foreach (var row in table.Rows)
        {
            var numberValue = row["Numbers"]; // the name of the column specified
        }
    }

As how to make your tests more meaningful, what I can say is that I personally would break this test into different scenarios. I would do one scenario for numbers that are shown as numbers other by the ones divided by 3 and another one those divided by 5.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top