best practices for writing first class unit tests
DESCRIPTION
A step by step demonstration of the practices and principles you can use to improve the quality and maintainability of your automated unit tests in .NET.TRANSCRIPT
![Page 1: Best practices for writing first class unit tests](https://reader035.vdocument.in/reader035/viewer/2022062418/5553b5abb4c905d9448b4d1f/html5/thumbnails/1.jpg)
© 2011 Aviva Solutions 12 april 2023
Writing First Class Unit Tests
Best Practices
Dennis Doomen | Principal Consultant | Aviva Solutions@ddoomen | www.dennisdoomen.net
![Page 2: Best practices for writing first class unit tests](https://reader035.vdocument.in/reader035/viewer/2022062418/5553b5abb4c905d9448b4d1f/html5/thumbnails/2.jpg)
© 2011 Aviva Solutions 12 april 2023
Unit tests…Are fast
Are automatedAre small
Run in-memory
Unit = Single class…or…
Dennis Doomen
![Page 3: Best practices for writing first class unit tests](https://reader035.vdocument.in/reader035/viewer/2022062418/5553b5abb4c905d9448b4d1f/html5/thumbnails/3.jpg)
© 2011 Aviva Solutions 12 april 2023
Integration tests…Can cross boundaries
Are slowerCan depend on external
resources
Dennis Doomen
![Page 4: Best practices for writing first class unit tests](https://reader035.vdocument.in/reader035/viewer/2022062418/5553b5abb4c905d9448b4d1f/html5/thumbnails/4.jpg)
© 2011 Aviva Solutions 12 april 2023
Other forms of testingSystem Testing
Usability TestingUser Acceptance Testing
ATDD
Dennis Doomen
![Page 5: Best practices for writing first class unit tests](https://reader035.vdocument.in/reader035/viewer/2022062418/5553b5abb4c905d9448b4d1f/html5/thumbnails/5.jpg)
© 2011 Aviva Solutions 12 april 2023
My First Attempt…
Dennis Doomen
![Page 6: Best practices for writing first class unit tests](https://reader035.vdocument.in/reader035/viewer/2022062418/5553b5abb4c905d9448b4d1f/html5/thumbnails/6.jpg)
© 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
![Page 7: Best practices for writing first class unit tests](https://reader035.vdocument.in/reader035/viewer/2022062418/5553b5abb4c905d9448b4d1f/html5/thumbnails/7.jpg)
© 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…
![Page 8: Best practices for writing first class unit tests](https://reader035.vdocument.in/reader035/viewer/2022062418/5553b5abb4c905d9448b4d1f/html5/thumbnails/8.jpg)
© 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…
![Page 9: Best practices for writing first class unit tests](https://reader035.vdocument.in/reader035/viewer/2022062418/5553b5abb4c905d9448b4d1f/html5/thumbnails/9.jpg)
© 2011 Aviva Solutions 12 april 2023My first attempt…
More improvements…Isolate The Ugly Stuff
Use Dependency Injection
![Page 10: Best practices for writing first class unit tests](https://reader035.vdocument.in/reader035/viewer/2022062418/5553b5abb4c905d9448b4d1f/html5/thumbnails/10.jpg)
© 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); }
![Page 11: Best practices for writing first class unit tests](https://reader035.vdocument.in/reader035/viewer/2022062418/5553b5abb4c905d9448b4d1f/html5/thumbnails/11.jpg)
© 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; } }
![Page 12: Best practices for writing first class unit tests](https://reader035.vdocument.in/reader035/viewer/2022062418/5553b5abb4c905d9448b4d1f/html5/thumbnails/12.jpg)
© 2011 Aviva Solutions 12 april 2023My first attempt…
Some more intentions…
![Page 13: Best practices for writing first class unit tests](https://reader035.vdocument.in/reader035/viewer/2022062418/5553b5abb4c905d9448b4d1f/html5/thumbnails/13.jpg)
© 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);
![Page 14: Best practices for writing first class unit tests](https://reader035.vdocument.in/reader035/viewer/2022062418/5553b5abb4c905d9448b4d1f/html5/thumbnails/14.jpg)
© 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; } }
![Page 15: Best practices for writing first class unit tests](https://reader035.vdocument.in/reader035/viewer/2022062418/5553b5abb4c905d9448b4d1f/html5/thumbnails/15.jpg)
© 2011 Aviva Solutions 12 april 2023My first attempt…
Arrange…act…assert…
![Page 16: Best practices for writing first class unit tests](https://reader035.vdocument.in/reader035/viewer/2022062418/5553b5abb4c905d9448b4d1f/html5/thumbnails/16.jpg)
© 2011 Aviva Solutions 12 april 2023My first attempt…
State versus interaction
![Page 17: Best practices for writing first class unit tests](https://reader035.vdocument.in/reader035/viewer/2022062418/5553b5abb4c905d9448b4d1f/html5/thumbnails/17.jpg)
© 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
![Page 18: Best practices for writing first class unit tests](https://reader035.vdocument.in/reader035/viewer/2022062418/5553b5abb4c905d9448b4d1f/html5/thumbnails/18.jpg)
© 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");
![Page 19: Best practices for writing first class unit tests](https://reader035.vdocument.in/reader035/viewer/2022062418/5553b5abb4c905d9448b4d1f/html5/thumbnails/19.jpg)
© 2011 Aviva Solutions 12 april 2023My first attempt…
AAA versus BDD-style
![Page 20: Best practices for writing first class unit tests](https://reader035.vdocument.in/reader035/viewer/2022062418/5553b5abb4c905d9448b4d1f/html5/thumbnails/20.jpg)
© 2011 Aviva Solutions 12 april 2023
And now for some faking…
![Page 21: Best practices for writing first class unit tests](https://reader035.vdocument.in/reader035/viewer/2022062418/5553b5abb4c905d9448b4d1f/html5/thumbnails/21.jpg)
© 2011 Aviva Solutions 12 april 2023
Karl Seguin wrote:Refusing
Getting too excitedTesting everything!Integration testingDiscover mocking
Mocking everythingBecoming effective
28 May 2009Dennis Doomen
![Page 22: Best practices for writing first class unit tests](https://reader035.vdocument.in/reader035/viewer/2022062418/5553b5abb4c905d9448b4d1f/html5/thumbnails/22.jpg)
© 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