Definitions of TDD
Test oriented development
• Having unit tests or integration tests in the code and write
them out either before or after writing the code. The code
has lots of tests and the value of tests is recognized. Design
probably exists before code writing.
Definitions of TDD
Test driven development or/and design
• Test Driven Development: The idea of writing your code in a
test-first manner. You may already have an existing design in
place. Tests are used to enhance the design.
• Test Driven Design: The idea of using a test-first approach as
a fully fledged design technique, where tests are a bonus but
the idea is to drive full design from little to no design
whatsoever. Tests are used to create the design.
Two levels of TDD
Acceptance TDD (ATDD)
• With ATDD you write a single acceptance test, and then just
enough production functionality/code to fulfill that test.
• The goal of ATDD is to specify detailed, executable
requirements for your solution on a just in time (JIT) basis.
ATDD is also called Behavior Driven Development (BDD).
Two levels of TDD
Developer TDD (TDD)
• With developer TDD you write a single developer test,
sometimes inaccurately referred to as a unit test, and then just
enough production code to fulfill that test.
• The goal of developer TDD is to specify a detailed,
executable design for your solution on a JIT basis.
Developer TDD is often simply called TDD.
Two levels of TDD
"Ideally, you'll write a single acceptance test, then to implement
the production code required to fulfill that test you'll take a
developer TDD approach."
Red-Green-Refactor
Red-Green-Refactor
Fail: Write a failing test to prove code or functionality is missing
• A programmer taking a TDD approach refuses to write a new
function until there is first a test that fails because that
function isn’t present (pair programming can help).
Pass: Make the test pass by writing production code that meets
the expectations
• By focusing on writing only the code necessary to pass tests,
designs can be cleaner and clearer than is often achieved by
other methods.
Refactor: Now the code can be cleaned up as necessary
• By re-running the tests, the developer can be confident that
code refactoring is not damaging any existing functionality.
DESIGN
Values of TDD
o Is about design specification not just validation
o Helps think through requirements before coding
o Helps focus on clean design and code
o Forces more testable and decoupled program structure
o Results in high code coverage
o Tests can serve as software documentation
o Tests can serve as refactoring safety net
o Automatic regression testing that can provide more specific clues of
defects (faster debugging and fixing)
o Conflicting tests can sometimes point out problems in customer
requirements
Unit Tests
A unit test should have the following properties:
• It should be automated and repeatable.
• It should be easy to implement.
• Once it’s written, it should remain for future use.
• Anyone should be able to run it.
• It should run at the push of a button.
• It should run quickly.
A unit test usually comprises 3 main actions:
• Arrange objects, creating and setting them up as necessary.
• Act on an object.
• Assert that something is as expected.
String Calculator
1. Create a simple string calculator with a method int Sum(string
numbers)
2. The method can take string of comma delimited 1, 2 or more
numbers, and will return the sum of the numbers
3. For any invalid string input it will return 0
First failing test
Both SHOULD & SHOULD NOT
So far…
• Had the chance to think about requirements and behaviors
• Didn’t need to worry about errors I’d see if I needed to run
this program to check the results
• Could focus on the design of overall structure and first
method.
• Designed and implemented the first method without
depending on the concrete implementation of the other 2
methods it calls (decoupling)
Parser
Adder
Refactor Parser > Run tests
Refactor Calculator > Run tests
Values of TDD, again
• Is about design specification not just validation
• Helps think through requirements before coding
• Helps focus on clean design and code
• Forces more testable and decoupled program structure
• Results in high code coverage
• Tests can serve as software documentation
• Tests can serve as refactoring safety net
• Automatic regression testing that can provide more specific clues of
defects (faster debugging and fixing)
• Conflicting tests can sometimes point out problems in customer
requirements
Pillars of good unit tests
Trustworthiness
• Trustworthy tests don’t have bugs and test the right things.
Developers can accept the test results with confidence.
Maintainability
• Ruin project schedule. Risk loosing the tests when the project
is put on a more aggressive schedule.
Readability
• Foundation of the other 2 pillars.
Trustworthiness: Test only one thing
Multiple asserts
• Harder to gave the test a more specific name
• After a failure, subsequent asserts aren’t executed; other
possible symptoms that could discover the problem are
missing
Multiple mocks (verifying whether the object under test
interacted as expected)
• There should be no more than one mock
• All other fake objects will act as stubs
Trustworthiness: Test only one thing
Solutions
• Create a separate test for each assert
• Use parameterized tests (EXAMPLE)
Fail and stop
Separate tests
Data-driven unit tests
Parameterized test
Extending MSTest > VS2012
Trustworthiness: Avoid test logic
switch, if-else, foreach, for, while, try-catch...
• The chances of having bugs in the tests increase
• A test that contains logic is usually testing more than one
thing at a time, which isn’t recommended, because the test is
less readable and more fragile.
Trustworthiness…
Make tests easy to run
• Better organized (unit test green zone, categories, test lists),
consistent results...
Assure code coverage
• In TDD because no more code is written than necessary to
pass a failing test case, automated tests tend to cover every
code path
Maintainability: Avoid testing private
or protected methods
• Private method tells developers that they can change the
implementation without worrying much about unknown
code that uses it.
• Testing private methods may lead to breaking tests, even
though the overall functionality is correct.
• Wanting to test a method means that it has a known behavior
or contract against the calling code.
• Making it public, extracting to class, making it static, making
it internal (least favorite)
Maintainability: Removing test code
duplication
Solutions
• Arrange with shared factory method, which can take
parameters and return values
• Initialize method
• Initialize methods should only contain code that applies to all the
tests in the current test class, or it will be harder to understand.
• Refactor to avoid long and hard to understand initialize method
• Create shared mocks/stubs in initialize method? Sometimes let
each test to call the shared helper method to create them for
better readability.
Maintainability: Enforcing test
isolation
Anti-patterns
• Hidden test call: Tests contain direct calls to other tests, which
causes tests to depend on one another
• Constrained test order: Tests are coded to expect a specific
state created by running other tests
• Shared-state corruption: Tests touch shared resources without
first initializing the resources or cleaning those up after testing
Solutions
• Flow testing - do integration testing instead
• Initialize and cleanup for each test
Maintainability: Avoiding testing
multiple aspects of the same object
• If we need to validate a BOX object, we may need one assert
for width, one assert to height, one assert for length, one
assert for material...
• Override Equals() method
Readability
Asserting with meaning
• Custom message
Separating asserts from actions
• “NO” Assert.AreEqual(COULD_NOT_READ_FILE,
log.GetLineCount("abc.txt"));
Initialize and cleanup
• Developers may not realize that there are mock objects set
up in initialize method. It’s more readable to initialize mock
objects directly in the test, with all their expectations. Can be
refactored into factory/helper methods.
Readability
Naming unit tests, basically 3 parts
• The name of the method being tested
• The scenario under which it’s being tested
• The expected behavior when the scenario is invoked
Naming variables
Each class stands
for a context
Use attributes to categorize tests
Use test lists
“TDD should be treated as an an approach (design aide), not just
as a task”
“Test Driven Development, done right, should make developers
highly aware of design pitfalls like tight coupling, violations of
SRP (Single Responsibility Principle), etc.”
“TDD = Refactoring + TFD”
References
http://artofunittesting.com/
http://en.wikipedia.org/wiki/Test-driven_development
http://www.agiledata.org/essays/tdd.html
http://www.pathfindersolns.com/resources/industry-glossary/tdd/
http://osherove.com/blog/2007/10/8/the-various-meanings-of-tdd.html
http://stackoverflow.com/questions/7538744/is-test-driven-development-the-same-as-test-
driven-design
http://stackoverflow.com/questions/80243/does-test-driven-development-take-the-focus-from-
design
http://stephenwalther.com/archive/2009/04/11/tdd-tests-are-not-unit-tests.aspx
http://biblio.gdinwiddie.com/biblio/StudiesOfTestDrivenDevelopment
http://elegantcode.com/2008/09/08/bdd-test-naming-experiment/
http://mrclyfar.blogspot.com/2010/02/amazing-mapping-demo-at-ted-2010.html
http://www.softwaretestinghelp.com/how-to-test-software-requirements-specification-srs/
http://davesquared.net/2009/10/calculators-and-tale-of-two-tdds-pt-1.html
http://davesquared.net/2009/10/calculators-and-tale-of-two-tdds-pt-2.html
http://www.shirmanov.com/2011/06/mstest-expectedexception-and-code.html

Test-Driven Development

  • 1.
    Definitions of TDD Testoriented development • Having unit tests or integration tests in the code and write them out either before or after writing the code. The code has lots of tests and the value of tests is recognized. Design probably exists before code writing.
  • 2.
    Definitions of TDD Testdriven development or/and design • Test Driven Development: The idea of writing your code in a test-first manner. You may already have an existing design in place. Tests are used to enhance the design. • Test Driven Design: The idea of using a test-first approach as a fully fledged design technique, where tests are a bonus but the idea is to drive full design from little to no design whatsoever. Tests are used to create the design.
  • 3.
    Two levels ofTDD Acceptance TDD (ATDD) • With ATDD you write a single acceptance test, and then just enough production functionality/code to fulfill that test. • The goal of ATDD is to specify detailed, executable requirements for your solution on a just in time (JIT) basis. ATDD is also called Behavior Driven Development (BDD).
  • 4.
    Two levels ofTDD Developer TDD (TDD) • With developer TDD you write a single developer test, sometimes inaccurately referred to as a unit test, and then just enough production code to fulfill that test. • The goal of developer TDD is to specify a detailed, executable design for your solution on a JIT basis. Developer TDD is often simply called TDD.
  • 5.
    Two levels ofTDD "Ideally, you'll write a single acceptance test, then to implement the production code required to fulfill that test you'll take a developer TDD approach."
  • 6.
  • 7.
    Red-Green-Refactor Fail: Write afailing test to prove code or functionality is missing • A programmer taking a TDD approach refuses to write a new function until there is first a test that fails because that function isn’t present (pair programming can help). Pass: Make the test pass by writing production code that meets the expectations • By focusing on writing only the code necessary to pass tests, designs can be cleaner and clearer than is often achieved by other methods. Refactor: Now the code can be cleaned up as necessary • By re-running the tests, the developer can be confident that code refactoring is not damaging any existing functionality. DESIGN
  • 8.
    Values of TDD oIs about design specification not just validation o Helps think through requirements before coding o Helps focus on clean design and code o Forces more testable and decoupled program structure o Results in high code coverage o Tests can serve as software documentation o Tests can serve as refactoring safety net o Automatic regression testing that can provide more specific clues of defects (faster debugging and fixing) o Conflicting tests can sometimes point out problems in customer requirements
  • 9.
    Unit Tests A unittest should have the following properties: • It should be automated and repeatable. • It should be easy to implement. • Once it’s written, it should remain for future use. • Anyone should be able to run it. • It should run at the push of a button. • It should run quickly. A unit test usually comprises 3 main actions: • Arrange objects, creating and setting them up as necessary. • Act on an object. • Assert that something is as expected.
  • 10.
    String Calculator 1. Createa simple string calculator with a method int Sum(string numbers) 2. The method can take string of comma delimited 1, 2 or more numbers, and will return the sum of the numbers 3. For any invalid string input it will return 0
  • 11.
  • 15.
    Both SHOULD &SHOULD NOT
  • 17.
    So far… • Hadthe chance to think about requirements and behaviors • Didn’t need to worry about errors I’d see if I needed to run this program to check the results • Could focus on the design of overall structure and first method. • Designed and implemented the first method without depending on the concrete implementation of the other 2 methods it calls (decoupling)
  • 18.
  • 21.
    Refactor Parser >Run tests Refactor Calculator > Run tests
  • 22.
    Values of TDD,again • Is about design specification not just validation • Helps think through requirements before coding • Helps focus on clean design and code • Forces more testable and decoupled program structure • Results in high code coverage • Tests can serve as software documentation • Tests can serve as refactoring safety net • Automatic regression testing that can provide more specific clues of defects (faster debugging and fixing) • Conflicting tests can sometimes point out problems in customer requirements
  • 23.
    Pillars of goodunit tests Trustworthiness • Trustworthy tests don’t have bugs and test the right things. Developers can accept the test results with confidence. Maintainability • Ruin project schedule. Risk loosing the tests when the project is put on a more aggressive schedule. Readability • Foundation of the other 2 pillars.
  • 24.
    Trustworthiness: Test onlyone thing Multiple asserts • Harder to gave the test a more specific name • After a failure, subsequent asserts aren’t executed; other possible symptoms that could discover the problem are missing Multiple mocks (verifying whether the object under test interacted as expected) • There should be no more than one mock • All other fake objects will act as stubs
  • 25.
    Trustworthiness: Test onlyone thing Solutions • Create a separate test for each assert • Use parameterized tests (EXAMPLE)
  • 26.
  • 27.
  • 28.
  • 30.
  • 31.
    Trustworthiness: Avoid testlogic switch, if-else, foreach, for, while, try-catch... • The chances of having bugs in the tests increase • A test that contains logic is usually testing more than one thing at a time, which isn’t recommended, because the test is less readable and more fragile.
  • 32.
    Trustworthiness… Make tests easyto run • Better organized (unit test green zone, categories, test lists), consistent results... Assure code coverage • In TDD because no more code is written than necessary to pass a failing test case, automated tests tend to cover every code path
  • 33.
    Maintainability: Avoid testingprivate or protected methods • Private method tells developers that they can change the implementation without worrying much about unknown code that uses it. • Testing private methods may lead to breaking tests, even though the overall functionality is correct. • Wanting to test a method means that it has a known behavior or contract against the calling code. • Making it public, extracting to class, making it static, making it internal (least favorite)
  • 34.
    Maintainability: Removing testcode duplication Solutions • Arrange with shared factory method, which can take parameters and return values • Initialize method • Initialize methods should only contain code that applies to all the tests in the current test class, or it will be harder to understand. • Refactor to avoid long and hard to understand initialize method • Create shared mocks/stubs in initialize method? Sometimes let each test to call the shared helper method to create them for better readability.
  • 35.
    Maintainability: Enforcing test isolation Anti-patterns •Hidden test call: Tests contain direct calls to other tests, which causes tests to depend on one another • Constrained test order: Tests are coded to expect a specific state created by running other tests • Shared-state corruption: Tests touch shared resources without first initializing the resources or cleaning those up after testing Solutions • Flow testing - do integration testing instead • Initialize and cleanup for each test
  • 36.
    Maintainability: Avoiding testing multipleaspects of the same object • If we need to validate a BOX object, we may need one assert for width, one assert to height, one assert for length, one assert for material... • Override Equals() method
  • 37.
    Readability Asserting with meaning •Custom message Separating asserts from actions • “NO” Assert.AreEqual(COULD_NOT_READ_FILE, log.GetLineCount("abc.txt")); Initialize and cleanup • Developers may not realize that there are mock objects set up in initialize method. It’s more readable to initialize mock objects directly in the test, with all their expectations. Can be refactored into factory/helper methods.
  • 38.
    Readability Naming unit tests,basically 3 parts • The name of the method being tested • The scenario under which it’s being tested • The expected behavior when the scenario is invoked Naming variables
  • 40.
  • 41.
    Use attributes tocategorize tests
  • 42.
  • 43.
    “TDD should betreated as an an approach (design aide), not just as a task” “Test Driven Development, done right, should make developers highly aware of design pitfalls like tight coupling, violations of SRP (Single Responsibility Principle), etc.” “TDD = Refactoring + TFD”
  • 44.
    References http://artofunittesting.com/ http://en.wikipedia.org/wiki/Test-driven_development http://www.agiledata.org/essays/tdd.html http://www.pathfindersolns.com/resources/industry-glossary/tdd/ http://osherove.com/blog/2007/10/8/the-various-meanings-of-tdd.html http://stackoverflow.com/questions/7538744/is-test-driven-development-the-same-as-test- driven-design http://stackoverflow.com/questions/80243/does-test-driven-development-take-the-focus-from- design http://stephenwalther.com/archive/2009/04/11/tdd-tests-are-not-unit-tests.aspx http://biblio.gdinwiddie.com/biblio/StudiesOfTestDrivenDevelopment http://elegantcode.com/2008/09/08/bdd-test-naming-experiment/ http://mrclyfar.blogspot.com/2010/02/amazing-mapping-demo-at-ted-2010.html http://www.softwaretestinghelp.com/how-to-test-software-requirements-specification-srs/ http://davesquared.net/2009/10/calculators-and-tale-of-two-tdds-pt-1.html http://davesquared.net/2009/10/calculators-and-tale-of-two-tdds-pt-2.html http://www.shirmanov.com/2011/06/mstest-expectedexception-and-code.html