It appears (IMHO, and Googlers') that MS's Test Explorer is shiite.
Better runners are: NUnit, TestDriven.NET, ReSharper, etc.
(Optional)
Writing Behaviour Driven Development tests:
- To Install BDDfy (http://docs.teststack.net/bddfy/),
run from the NuGet Package Manager Console:
Install-Package TestStack.BDDfy
Writing Unit Tests:
- Create a .UnitTests VisualStudio Project for each Project you wish to test
- Use the NUnit syntax (i.e. annotations, see included book or google it) in your tests
- To Install NUnit (for the Tests Project, not the SystemUnderTest), run from the NuGet Package Manager Console:
Install-Package NUnit
Running (and Debugging) Unit Tests in VS:
- To install TestDriven.NET (a Test runner; ReSharper is another), run the installer EXE.
- Use TestDriven.NET in VisualStudio context menu
i.e. right-click in the Solution and/or Project containing tests or right in a test method in the file Editor
and select:
- 'Run Test(s)' to run i.e. NOT 'Run Tests' [ONLY when in Editor], that uses Microsofts runner...
- 'Test With > Debugger' to debug
Sample code follows:
Largest.cs
using System;
namespace Largest
{
public class Cmp
{
public static int Largest(int[] list)
{
if (list.Length == 0)
{
throw new ArgumentException("Empty list");
}
int index, max = list[0];
for (index = 0; index < list.Length; index++)
{
if (list[index] > max)
{
max = list[index];
}
}
return max;
}
}
}
LargestTest.cs
using System;
using NUnit.Framework;
{
[TestFixture]
public class LargestTest
{
[Test]
public void LargestOf3()
{
int[] numbers = new int[] { 9, 8, 7 };
Assert.That(Cmp.Largest(numbers), Is.EqualTo(9));
numbers = new int[] { 8, 9, 7 };
Assert.That(Cmp.Largest(numbers), Is.EqualTo(9));
numbers = new int[] { 7, 8, 9 };
Assert.That(Cmp.Largest(numbers), Is.EqualTo(9));
}
[Test]
[ExpectedException(typeof(ArgumentException))]
public void Empty()
{
Cmp.Largest(new int[] { });
}
[Test]
public void LargestOf3Alt()
{
Assert.That(Cmp.Largest(new int[]{ 8, 9, 7 }), Is.EqualTo(9));
}
[Test]
public void Negative()
{
int[] negatives = new int[] { -9, -8, -7 };
Assert.That(Cmp.Largest(negatives), Is.EqualTo(-7));
}
}
}
BDDDemo.cs
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using TestStack.BDDfy;
namespace BDDfy.Samples.Atm // Scenarios taken from http://dannorth.net/introducing-bdd/
{
[TestClass]
[Story(
AsA = "As an Account Holder",
IWant = "I want to withdraw cash from an ATM",
SoThat = "So that I can get money when the bank is closed")]
public class AccountHolderWithdrawsCash
{
[TestMethod]
public void AccountHasInsufficientFund()
{
new AccountHasInsufficientFund().BDDfy();
}
[TestMethod]
public void CardHasBeenDisabled()
{
new CardHasBeenDisabled().BDDfy();
}
[TestMethod]
public void AccountHasSufficientFund()
{
new AccountHasSufficientFund()
.Given(s => s.GivenTheAccountBalanceIs(100), "Given the account balance is $100")
.And(s => s.AndTheCardIsValid())
.And(s => s.AndTheMachineContainsEnoughMoney())
.When(s => s.WhenTheAccountHolderRequests(20), "When the account holder requests $20")
.Then(s => s.ThenTheAtmShouldDispense(20), "Then the ATM should dispense $20")
.And(s => s.AndTheAccountBalanceShouldBe(80), "And the account balance should be $80")
.And(s => s.AndTheCardShouldBeReturned())
.BDDfy();
}
}
[TestClass]
public class AccountHasSufficientFund
{
private Card _card;
private Atm _atm;
public void GivenTheAccountBalanceIs(int balance)
{
_card = new Card(true, balance);
}
public void AndTheCardIsValid()
{
}
public void AndTheMachineContainsEnoughMoney()
{
_atm = new Atm(100);
}
public void WhenTheAccountHolderRequests(int moneyRequest)
{
_atm.RequestMoney(_card, moneyRequest);
}
public void ThenTheAtmShouldDispense(int dispensedMoney)
{
Assert.AreEqual(dispensedMoney, _atm.DispenseValue);
}
public void AndTheAccountBalanceShouldBe(int balance)
{
Assert.AreEqual(balance, _card.AccountBalance);
}
public void AndTheCardShouldBeReturned()
{
Assert.IsFalse(_atm.CardIsRetained);
}
}
[TestClass]
public class AccountHasInsufficientFund
{
private Card _card;
private Atm _atm;
// You can override step text using executable attributes
[Given("Given the account balance is $10")]
void GivenTheAccountBalanceIs10()
{
_card = new Card(true, 10);
}
void AndGivenTheCardIsValid()
{
}
void AndGivenTheMachineContainsEnoughMoney()
{
_atm = new Atm(100);
}
[When("When the account holder requests $20")]
void WhenTheAccountHolderRequests20()
{
_atm.RequestMoney(_card, 20);
}
void ThenTheAtmShouldNotDispenseAnyMoney()
{
Assert.AreEqual(0, _atm.DispenseValue);
}
void AndTheAtmShouldSayThereAreInsufficientFunds()
{
Assert.AreEqual(DisplayMessage.InsufficientFunds, _atm.Message);
}
void AndTheAccountBalanceShouldBe10()
{
Assert.AreEqual(10, _card.AccountBalance);
}
void AndTheCardShouldBeReturned()
{
Assert.IsFalse(_atm.CardIsRetained);
}
[TestMethod]
public void Execute()
{
this.BDDfy();
}
}
[TestClass]
public class CardHasBeenDisabled
{
private Card _card;
Atm _subject;
void GivenTheCardIsDisabled()
{
_card = new Card(false, 100);
_subject = new Atm(100);
}
void WhenTheAccountHolderRequestsMoney()
{
_subject.RequestMoney(_card, 20);
}
void ThenTheAtmShouldRetainTheCard()
{
Assert.IsTrue(_subject.CardIsRetained);
}
void AndTheAtmShouldSayTheCardHasBeenRetained()
{
Assert.AreEqual(DisplayMessage.CardIsRetained, _subject.Message);
}
[TestMethod]
public void Execute()
{
this.BDDfy();
}
}
}
BDDDomainObjects
namespace BDDfy.Samples.Atm
{
public class Atm
{
public int ExistingCash { get; private set; }
public Atm(int existingCash)
{
ExistingCash = existingCash;
}
public void RequestMoney(Card card, int request)
{
if (!card.Enabled)
{
CardIsRetained = true;
Message = DisplayMessage.CardIsRetained;
return;
}
if (card.AccountBalance < request)
{
Message = DisplayMessage.InsufficientFunds;
return;
}
DispenseValue = request;
card.AccountBalance -= request;
}
public int DispenseValue { get; set; }
public bool CardIsRetained { get; private set; }
public DisplayMessage Message { get; private set; }
}
public class Card
{
public int AccountBalance { get; set; }
private readonly bool _enabled;
public Card(bool enabled, int accountBalance)
{
AccountBalance = accountBalance;
_enabled = enabled;
}
public bool Enabled
{
get { return _enabled; }
}
}
public enum DisplayMessage
{
None = 0,
CardIsRetained,
InsufficientFunds
}
}
Sample output
------ Test started: Assembly: UnitTests.dll ------
Story: Account holder withdraws cash
As an Account Holder
I want to withdraw cash from an ATM
So that I can get money when the bank is closed
Scenario: Account has insufficient fund
Given the account balance is $10
And the card is valid
And the machine contains enough money
When the account holder requests $20
Then the atm should not dispense any money
And the atm should say there are insufficient funds
And the account balance should be 10
And the card should be returned
Story: Account holder withdraws cash
As an Account Holder
I want to withdraw cash from an ATM
So that I can get money when the bank is closed
Scenario: Card has been disabled
Given the card is disabled
When the account holder requests money
Then the atm should retain the card
And the atm should say the card has been retained
Story: Account holder withdraws cash
As an Account Holder
I want to withdraw cash from an ATM
So that I can get money when the bank is closed
Scenario:
Given the account balance is $100
And the card is valid
And the machine contains enough money
When the account holder requests $20
Then the ATM should dispense $20
And the account balance should be $80
And the card should be returned
3 passed, 0 failed, 0 skipped, took 0.89 seconds (MSTest 10.0).