A Better Way to Setup Test Data Poya Manouchehri @PoyaManouchehri [email protected] http://askpoya.wordpress.com/
Nov 11, 2014
A Better Way to SetupTest DataPoya Manouchehri
@[email protected]://askpoya.wordpress.com/
1. Intent is Unclear:• What is 160?• Is nationality important?
2. Test is Brittle:• Changing the constructor will break many tests
[Test]public void GivenAPersonUnder16_WhenAssigningADriverLicense_ThenAnExceptionIsThrown(){ // Arrange var sarah = new Person("Sarah", "Smith", DateTime.Today.AddYears(-15), 160, "Australian");
// Act / Assert Assert.Throws<InvalidOperationException>(() => sarah.AssignDriverLicense(DriverLicenseType.Automatic));}
public static partial class ObjectMother{ public static class Persons { public static Person FifteenYearOldSarah { get { return new Person("Sarah", "Smith", DateTime.Today.AddYears(-17), 160, "Australian"); } }
public static Person BrazilianRafael { get { return new Person("Rafael", "Gomez", new DateTime(1985, 12 , 2), 177, “Brazilian") } } }}
Object Mother Pattern
[Test]public void GivenAPersonUnder16_WhenAssigningADriverLicense_ThenAnExceptionIsThrown(){ var sarah = ObjectMother.Persons.FifteenYearOldSarah;
Assert.Throws<InvalidOperationException>(() => sarah.AssignDriverLicense(DriverLicenseType.Automatic));}
Object Mother Pattern
var person = new PersonBuilder() .WithName("Michael", "Jackson") .BornOn(new DateTime(1958, 8, 29)) .WithHeight(175) .WithNationality("American") .WhoHasDriverLicense(DriverLicenseType.Truck) .Build();
Builder Pattern
[Test]public void GivenAPersonUnder16_WhenAssigningADriverLicense_ThenAnExceptionIsThrown(){ var person = new PersonBuilder() .BornOn(DateTime.Today.AddYears(-15)) .Build();
Assert.Throws<InvalidOperationException>(() => person.AssignDriverLicense(DriverLicenseType.Automatic));}
Builder Pattern
[Test]public void GivenAPersonUnder16_WhenAssigningADriverLicense_ThenAnExceptionIsThrown(){ var person = ObjectMother.Persons.Sarah .BornOn(DateTime.Today.AddYears(-15)) .Build();
Assert.Throws<InvalidOperationException>(() => person.AssignDriverLicense(DriverLicenseType.Automatic));}
Builder Pattern
var people = PersonBuilder.CreateListOfSize(10) .All().Do(p => p.WithNationality("Australian")) .TheFirst(2).Do(p => p.BornOn(new DateTime(1980, 1, 1))) .TheNext(3).Do(p => p.BornOn(new DateTime(1974, 10, 15))) .Random(2).Do(p => p.WithHeight(180)) .BuildList<Person, PersonBuilder>();
Building Collections with NBuilder
var people = new[]{ new PersonBuilder().WithNationality("Australian").BornOn(new DateTime(1980, 1, 1)).Build(), new PersonBuilder().WithNationality("Australian").BornOn(new DateTime(1980, 1, 1)) .WithHeight(180).Build(), new PersonBuilder().WithNationality("Australian").BornOn(new DateTime(1974, 10, 15)).Build(), new PersonBuilder().WithNationality("Australian").BornOn(new DateTime(1974, 10, 15)) .WithHeight(180).Build(), new PersonBuilder().WithNationality("Australian").BornOn(new DateTime(1974, 10, 15)).Build()};
public class TransportCentre{ ...
public void PerformTruckDrivingTest(Person person) { // Do the test
person.AssignDriverLicense(DriverLicenseType.Truck); }}
Building Mocks with NSubstitute
[Test]public void GivenAPerson_WhenTruckDrivingTestIsCompleted_ThenThePersonIsAssignedALicense(){ var person = ObjectMother.Persons.John.Build(); var transportCentre = ObjectMother.TransportCentres.BrisbaneCityCentre.Build();
transportCentre.PerformTruckDrivingTest(person);
Assert.That(person.DriverLicenseType, Is.EqualTo(DriverLicenseType.Truck));}
What’s the actual “Unit” under test?• PerformTruckDrivingTest()• Not Person.AssignDriverLicense()
Building Mocks with NSubstitute
[Test]public void GivenAPerson_WhenTruckDrivingTestIsCompleted_ThenThePersonIsAssignedALicense(){ var person = ObjectMother.Persons.John.AsProxy().Build(); var transportCentre = ObjectMother.TransportCentres.BrisbaneCityCentre.Build();
transportCentre.PerformTruckDrivingTest(person);
person.Received().AssignDriverLicense(DriverLicenseType.Truck);}
Building Mocks with NSubstitute
What’s the actual “Unit” under test?• PerformTruckDrivingTest()• Not Person.AssignDriverLicense()
Building Mocks with NSubstitute
Caveats:• Requires a protected parameteress constructor• Requires the virtual keyword for any properties or methods that
need to be mocked
GitHub: https://github.com/robdmoore/NTestDataBuilder
Twitter: @robdmoore
NTestDataBuilder
Questions