Test Driven Development
Introduction
Costs
The cost of software according to this course was
Tests are split into three categories
- Does what was asked for
- Responds appropriately to bad input
- Acceptable Performance
Red Green Refactor
Start by writing tests with no code, write until test pass, refactor code. This is an iterative approach.
Benefits
- Requirements are verified by the tests
- Regression issues raised early
- Costs of maintenance is lowered
- Design first, when writing the tests first we are designing what they want
- Reduces over engineering
- Easy to know where you are in the project
Different Types of Testing
Types of Testing
- Unit Testing
- Functional Testing (UI/End-to-End)
- Integrating Testing
- User Acceptance Testing
Testing Approaches
- Black Box testing (testing the interface)
- White Box testing (testing internal aspects)
Tools
Some well known tools are
- Selenium
- Watir
- VS Coded UI
- Test Studio (Telerik)
- Silk Test (Micro Focus)
Terminology
- Test
- Test Suite (Group of tests)
- Before/After hooks to set up and tear down
- Assert, eg. isTrue, isNull, areEqual
- Test Execution
- Test Runner (async/sync)
Example Fizz Buzz
Requirements
This has the following requirements Given a positive number
- Divisible by 3 => "Fizz"
- Divisible by 5 => "Buzz"
- Divisible by 3 & 5 => "Fizz Buzz"
- Otherwise => Number
Step 1
Create initial test
private FizzBuzzService _fizzBuzzService;
public FizzBuzzTests() {
_fizzBuzzService = new FizzBuzzService();
}
[TestMethod]
public void ShouldPrintNumber() {
Assert.AreEqual("1", _fizzBuzzService.Print(1));
}
Step 2
So lets build out tests up as we go until we get to.
...
[TestMethod]
public void ShouldPrintFizz()
{
Assert.AreEqual("Fizz", _fizzBuzz.Print(3));
}
[TestMethod]
public void ShouldPrintBuzz()
{
Assert.AreEqual("Buzz", _fizzBuzz.Print(5));
Assert.AreEqual("Buzz", _fizzBuzz.Print(10));
}
[TestMethod]
public void ShouldPrintFizzBuzz()
{
Assert.AreEqual("FizzBuzz", _fizzBuzz.Print(15));
}
...
Techniques
Dependency Injection
This is used in Frameworks all the time.
The problem is that if we did not create a service and inject it but instead created in the class we are testing, it would be far harder to get the service to be in the correct state for the test. But if the service is passed in we could easily mock the state to do the test.
public class Greeter {
private NameService nameService;
public Greeter() {
this.nameService = new NamService()
}
public string SayHello() {
return $"Hello, {this.nameService.GetName()}";
}
}