Nunit Framework vs SpecFlow Framework

Yan picture Yan · Nov 25, 2015 · Viewed 10.1k times · Source

I am new to NUnit and confused with the SpecFlow Testing Framework and NUnit Testing Framework.

The existing project uses NUnit, something like this below. All the methods with [Test] attribute are displayed in the NUnit GUI (if I remove [Test] from the method, the test case is not display in NUnit GUI):

[TestFixture]
public class AccountTest
{
  [Test]
  public void TransferFunds()
  {
    Account source = new Account();
    source.Deposit(200m);
  }

  [Test]
  public void TransferWithInsufficientFunds()
  {
  }
}

When I code with SpecFlow in the same project, the SpecFlow framework is different, starting with [Given], [When], [Then]. And each SpecFlow scenario is displayed at the Nunit GUI.

What I am doing is replacing each [Test] method with one SpecFlow method. E.g.:

[Test]
public void TransferFunds()
{
  Account source = new Account();
  source.Deposit(200m);
}

Turns to

[Then(@"I Transfer Funds")]
public void ITransferFunds()
{
  Account source = new Account();
  source.Deposit(200m);
}

Here is my question:

  1. It looks like SpecFlow does not recognize the NUnit attributes [Test] or [Setup]. To do the project with SpecFlow, do I need to get rid of all NUnit framework and replace with SpecFlow's framework?

  2. I can see there is many articles talking about "SpecFlow + NUnit", but they are either with SpecFlow [Given], [When], [Then] or NUnit [Test], [TestCase]. How to make both work in one project or is my understanding of NUnit is totally wrong?

My question might be very entry level, thanks for the answers!

Answer

Maximo Dominguez picture Maximo Dominguez · Nov 25, 2015

Do I need to get rid of all NUnit framework and replace with SpecFlow's framework?

The first thing I think you need to understand is that NUnit and SpecFlow are not mutually exclusive.

SpecFlow as a whole has a lot of components, but what you need to understand now is that SpecFlow is used to bind feature files written in Gherkin to C# code that can be run by a test runner. That C# code has two parts, the auto-generated one, and the one written by you and your team.


The part written by you are those methods with the attributes Given, When, and Then. They are the step definitions (read more here). These bindings need to follow these rules:

  • Must be in a public class, marked with the [Binding] attribute.
  • Must be a public method.
  • Can be either a static or an instance method. If it is an instance method, the >* containing class will be instantiated once for every scenario.
  • Cannot have out or ref parameters.
  • Cannot have a return type.

The auto-generated part generates tests methods written using NUnit, MSTest, xUnit among other available unit test providers. As you can see, with the same Gherkin (here and here) you end up with different auto-generated files (here and here)


Let's take a look at a specific scenario (source)

Scenario: One single spare
    Given a new bowling game
    When I roll the following series:   3,7,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1
    Then my total score should be 29

If the Unit Test Provider is NUnit that step will generate the following test method (source):

[NUnit.Framework.TestAttribute()]
[NUnit.Framework.DescriptionAttribute("One single spare")]
public virtual void OneSingleSpare()
{
    TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("One single spare", ((string[])(null)));
#line 7
    this.ScenarioSetup(scenarioInfo);
#line 8
    testRunner.Given("a new bowling game");
#line 9
    testRunner.When("I roll the following series:\t3,7,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1");
#line 10
    testRunner.Then("my total score should be 29");
#line hidden
    testRunner.CollectScenarioErrors();
}

If the Unit Test Provider is xUnit that step will generate the following test method (source):

[Xunit.FactAttribute()]
[Xunit.TraitAttribute("FeatureTitle", "Score Calculation (alternative forms)")]
[Xunit.TraitAttribute("Description", "One single spare")]
public virtual void OneSingleSpare()
{
    TechTalk.SpecFlow.ScenarioInfo scenarioInfo = new TechTalk.SpecFlow.ScenarioInfo("One single spare", ((string[])(null)));
#line 7
    this.ScenarioSetup(scenarioInfo);
#line 8
    testRunner.Given("a new bowling game");
#line 9
    testRunner.When("I roll the following series:\t3,7,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1");
#line 10
    testRunner.Then("my total score should be 29");
#line hidden
    testRunner.CollectScenarioErrors();
}

No matter what Unit Test Provider you're using, your step definitions methods will look almost* the same (as you can see here for NUnit and here for xUnit).

There are a few different step definition styles you can use. They are described here

*The only difference might be your assertions.