Project Description

A simple class for extending unit testing frameworks with BDD-style (Given-When-Then) tests.

Background

Inspired by SpecFlow and SubSpec, I wanted a minimally intrusive BDD extension that provided the following capabilities:

  • fluent interface (ideally with minimal language noise) for testing Given-When-Then-style specifications within a single method;
  • support for parameterised / data-driven tests (e.g. TestCaseSource and Theory as found in NUnit, etc);
  • output formattable specifications in plain English;
  • ability to have multiple assertions per specification, and to have all assertions exercised even if one of them fails;
  • the extension should be unit test framework agnostic;
  • minimal footprint, with no additional plugins required (e.g. for Visual Studio, Resharper, etc.).

NUnit Example

[Test, TestCaseSource("DataForInsufficientFunds")]
public void AccountHasInsufficientFunds(int accountBalance, int withdrawlAmount)
{
    var atm = default(AutomatedTellerMachine);
    var card = default(Card);

    var cashInAtm = accountBalance + 10;

    IsSatisfiedBy(
        Scenario("Cardholder has insufficient funds")
            .Given("the ATM has {0}", cashInAtm)
                [() => atm = new AutomatedTellerMachine(cashInAtm)]
            .And("the account has {0}", accountBalance)
                [() => card = new Card(true, accountBalance)]

            .When("the account holder requests {0}", withdrawlAmount)
                [() => atm.RequestMoney(card, withdrawlAmount)]

            .Then("the ATM should dispense $0")
                [() => Assert.AreEqual(0, atm.DispenseValue)]
            .And("the account balance should be unchanged")
                [() => Assert.AreEqual(accountBalance, card.AccountBalance)]
            .And("the ATM should display Insufficient Funds")
                [() => Assert.AreEqual(DisplayMessage.InsufficientFunds, atm.Message)]

            .AsScript);
}

public static IEnumerable DataForInsufficientFunds
{
    get
    {
        yield return new TestCaseData(10, 20);
        yield return new TestCaseData(100, 110);
    }
}


Last edited May 17, 2012 at 10:20 AM by badscooter, version 4