Best practices for writing first class unit tests
-
Upload
dennis-doomen -
Category
Technology
-
view
2.402 -
download
2
description
Transcript of Best practices for writing first class unit tests
© 2011 Aviva Solutions 12 april 2023
Writing First Class Unit Tests
Best Practices
Dennis Doomen | Principal Consultant | Aviva Solutions@ddoomen | www.dennisdoomen.net
© 2011 Aviva Solutions 12 april 2023
Unit tests…Are fast
Are automatedAre small
Run in-memory
Unit = Single class…or…
Dennis Doomen
© 2011 Aviva Solutions 12 april 2023
Integration tests…Can cross boundaries
Are slowerCan depend on external
resources
Dennis Doomen
© 2011 Aviva Solutions 12 april 2023
Other forms of testingSystem Testing
Usability TestingUser Acceptance Testing
ATDD
Dennis Doomen
© 2011 Aviva Solutions 12 april 2023
My First Attempt…
Dennis Doomen
© 2011 Aviva Solutions 12 april 2023
[TestMethod] public void FindCustomersTest1() { var viewModel = new CustomerManagementViewModel(); string propertyChanged = ""; viewModel.PropertyChanged += (sender, args) => propertyChanged = args.PropertyName; viewModel.City = "Washington"; viewModel.MinimumAccountBalance = 10000;
viewModel.Find();
var customers = viewModel.Customers; Assert.AreEqual(2, customers.Count()); Assert.IsTrue(customers.Any(c => c.Id == 15)); Assert.IsTrue(customers.Any(c => c.Id == 81)); Assert.AreEqual("Customers", propertyChanged);
viewModel.City = ""; viewModel.MinimumAccountBalance = 0;
propertyChanged = "";
viewModel.Find();
Assert.AreEqual(102, viewModel.Customers.Count()); }
Intention RevealingSmall and focused
Clear cause and effectTest one condition
IndependentRepeatable
No side-effects
© 2011 Aviva Solutions 12 april 2023
If it is not important for the
test, it is very important not to
show it…
My first attempt…
© 2011 Aviva Solutions 12 april 2023
A small improvement… [TestMethod]
public void When_searching_it_should_account_for_the_city_and_minimal_account_balance() { }
My first attempt…
© 2011 Aviva Solutions 12 april 2023My first attempt…
More improvements…Isolate The Ugly Stuff
Use Dependency Injection
© 2011 Aviva Solutions 12 april 2023
[TestMethod] public void When_searching_it_should_account_for_the_city_and_minimal_account_balance() { var dummyCustomers = new[] { new Customer(), new Customer()};
var service = new ServiceAgentStub(); service.AddDummyCustomers(dummyCustomers);
var viewModel = new CustomerManagementViewModel(service) { City = "Washington", MinimumAccountBalance = 10000 };
string propertyChanged = null; viewModel.PropertyChanged += (sender, args) => propertyChanged = args.PropertyName;
viewModel.Find();
Assert.AreEqual(2, viewModel.Customers.Count()); CollectionAssert.AreEquivalent(viewModel.Customers.ToArray(), dummyCustomers);
Assert.AreEqual("Washington", service.City); Assert.AreEqual(10000, service.MinimumAccountBalance);
Assert.AreEqual("Customers", propertyChanged); }
© 2011 Aviva Solutions 12 april 2023
public class ServiceAgentStub : IServiceAgent { private List<Customer> dummyCustomers = new List<Customer>();
public decimal? MinimumAccountBalance { get; set; } public string City { get; set; }
public void AddDummyCustomers(params Customer[] customers) { dummyCustomers.AddRange(customers); }
public IEnumerable<Customer> FindCustomers(string city, decimal? minimumAccountBalance) { City = city; MinimumAccountBalance = minimumAccountBalance;
return dummyCustomers; } }
© 2011 Aviva Solutions 12 april 2023My first attempt…
Some more intentions…
© 2011 Aviva Solutions 12 april 2023
[TestMethod] public void When_searching_it_should_account_for_the_city_and_minimal_account_balance() { var dummyCustomers = new[] { new Customer(), new Customer()};
var service = new ServiceAgentStub(); service.AddDummyCustomers(customer1, customer2);
[TestMethod] public void When_searching_it_should_account_for_the_city_and_minimal_account_balance() { var someCustomer = new CustomerBuilder().Build(); var someOtherCustomer = new CustomerBuilder().Build();
var theServiceAgent = new ServiceAgentStub(); theServiceAgent.AddDummyCustomers(someCustomer, someOtherCustomer);
© 2011 Aviva Solutions 12 april 2023
public class CustomerBuilder : TestDataBuilder<Customer> { private static long nextId = 1; private string city = "Redmond"; private decimal accountBalance = 100;
protected override Customer OnBuild() { return new Customer { Id = nextId++, City = city, AccountBalance = accountBalance }; }
public CustomerBuilder InCity(string city) { this.city = city; return this; }
public CustomerBuilder WithAccountBalance(decimal accountBalance) { this.accountBalance = accountBalance; return this; } }
© 2011 Aviva Solutions 12 april 2023My first attempt…
Arrange…act…assert…
© 2011 Aviva Solutions 12 april 2023My first attempt…
State versus interaction
© 2011 Aviva Solutions 12 april 2023My first attempt…
Rules to ease unit testing…Test small before you test big
Prefer state-based testingKeep out of the debugger hell
© 2011 Aviva Solutions 12 april 2023
//------------------------------------------------------------------------------------------------------------------- // Assert //------------------------------------------------------------------------------------------------------------------- Assert.AreEqual(2, viewModel.Customers.Count()); var expectedCustomers = new[] { someCustomer, someOtherCustomer}; CollectionAssert.AreEquivalent(viewModel.Customers.ToArray(), expectedCustomers);
Assert.AreEqual("Washington", theServiceAgent.City); Assert.AreEqual(10000, theServiceAgent.MinimumAccountBalance);
Assert.AreEqual("Customers", changedPropertyName);
//------------------------------------------------------------------------------------------------------------------- // Assert //------------------------------------------------------------------------------------------------------------------- viewModel.Customers.Should().Equal(someCustomers);
theServiceAgent.City.Should().Be("Washington"); theServiceAgent.MinimumAccountBalance.Should().Be(10000m);
changedPropertyName.Should().Be("Customers");
© 2011 Aviva Solutions 12 april 2023My first attempt…
AAA versus BDD-style
© 2011 Aviva Solutions 12 april 2023
And now for some faking…
© 2011 Aviva Solutions 12 april 2023
Karl Seguin wrote:Refusing
Getting too excitedTesting everything!Integration testingDiscover mocking
Mocking everythingBecoming effective
28 May 2009Dennis Doomen
© 2011 Aviva Solutions 12 april 2023
Background InformationJeremy’s Laws of TDD, Test Data Builder, Applying Domain Driven Design (Jimmy Nillson), xUnit Patterns
Example Code, FrameworksSilverlight Cookbook, Fake It Easy, Fluent Assertions