SlideShare a Scribd company logo
Test & Behaviour
Driven Development
Lars Thorup
ZeaLake Software Consulting


March, 2012
Who is Lars Thorup?

●   Software developer/architect
    ●   C++, C# and JavaScript
    ●   Test Driven Development

●   Coach: Teaching agile and
    automated testing

●   Advisor: Assesses software
    projects and companies

●   Founder and CEO of
    BestBrains and ZeaLake
Why are we here today?
●   What is TDD/BDD?
    ●   Express expected behaviour before writing code

●   Why is TDD/BDD a good thing?
    ●   Enjoy more efficient and predictable course of development
    ●   Find and fix bugs faster
    ●   Prevent bugs from reappearing
    ●   Improve the design of our software
    ●   Reliable documentation

●   How do we do TDD/BDD?
    ●   Write test programs
    ●   Run the tests automatically
Workflow of TDD/BDD
    Think, talk
                  Idea

                          Test
                                   Failing
                                    test



                                                   Code


                      Good                   Succeeding
                     design      Refactor       test
BDD or TDD?
●   Behaviour first
    ●   makes more sense than "Test first"

●   Structure of test programs
    ●   Given <precondition>
    ●   When <invocation>
    ●   Then <expectation>

●   High level as well as low level
    ●   Testing user stories and requirements
    ●   Testing class design and algorithms

●   Communicate intent

●   Fast feedback
Different kinds of automated tests
●   Unit tests
    ●   Test individual pieces of code and the interaction between code
        blocks


●   System tests / acceptance tests
    ●   Verify the behaviour of the entire system against the requirements


●   Performance tests
    ●   Test non functional requirements
Unit tests or system tests?
●   Unit tests are efficient
    ●   Fast to run (hundreds per second)
    ●   Robust and predictable
    ●   Can be easy to write
    ●   Is written together with the code it is testing


●   System tests are thorough
    ●   Tests all layers together
    ●   Most efficient way to create a set of tests for existing code
    ●   Can be easier to read for non-technical people
Can we automate performance tests?
●   Performance tests are brittle
    ●   Tip: create performance trend curves instead
How do we run the tests automatically?
●   From our programming environment (IDE)
    ●   Command line: make test
    ●   Right click | Run Tests

●   On every commit
    ●   Setup a build server
    ●   Jenkins, TeamCity
    ●   Let the build server run all tests
    ●   Get build notifications
    ●   Keep the build green
    ●   Fixing a broken build has priority over any other development task
How can tests help improve our design?
●   The software design will evolve over time

●   A refactoring improves the design without changing
    behavior

●   Tests ensure that behavior is not
    accidentally changed


●   Without tests, refactoring is scary
    ●   and with no refactoring, the design decays over time


●   With tests, we have the courage to refactor
    ●   so we continually keep our design healthy
Are we wasting developer time writing tests?
●   No

●   Time spent writing tests is not taken from time spent coding
    ●   ... but from time otherwise spent on manual testing and debugging

●   The cost of a bug keeps
    increasing until we fix it

●   Find bugs faster
    ●   Avoid losing customer confidence
    ●   Free QA to do exploratory testing
        so they find the hard-to-find bugs
    ●   Spend less time trying to figure out
        what is causing the bug and how to fix it

●   Avoid spending time testing again
How do we get started?
●   When we have a lot of existing code without tests
    ●   Create a set of system tests to get a safety net


●   When we are writing new code
    ●   Write unit tests in conjunction with the new code


●   Set up a standard test environment for our specific
    application
    ●   Test data: Automate the creation of standard testdata in a local
        database
    ●   External dependencies: Write stubs to use in the tests
Maintainability
●   Stick to a pattern for your tests
    ●   E.g. Given-When-Then

●   Focus on readability over code duplication in test code

●   Write reusable helper classes (builders) to simplify tests
What does a real-world project look like?
●   wizerize.com
    ●   Web application: C# and JavaScript
    ●   3½ years of development, 3½ years in production
    ●   2-4 developers
    ●   40% test code, 60% production code (in lines of code)
    ●   71% code coverage of unit tests
    ●   872 unit tests – run in 1½ minute
    ●   72 system tests – run in 20 minutes
    ●   No functional errors seen by end users in production (yet)
Where can I read more?
●   http://googletesting.blogspot.com/

●   http://testdrivendeveloper.com/

●   http://codesheriff.blogspot.com/

●   http://www.zealake.com/category/test/
But what about:
●   Stubs & mocks

●   Test data

●   UI testing

●   SQL testing

●   JavaScript testing

●   Web Service testing

●   Legacy code
What is good design?
●   One element of good design is loose coupling
    ●   Use interfaces (for static languages)
    ●   Inject dependencies
                                   public void Trigger()
●   Avoid using new:               {
                                       var emailSvc = new EmailSvc();
                                       emailSvc.SendEmail();
                                   }


●   Inject dependencies instead:
               private IEmailSvc emailSvc;
               public Notifier(IEmailSvc emailSvc)
               {
                   this.emailSvc = emailSvc;
               }

               public void Trigger()
               {
                   emailSvc.SendEmail();
Stubs and mocks
●   When testing an object X, that depends on an object Y
    ●   replace the real Y with a fake Y

●   Benefits
    ●   Only test one thing (X) at a time
                                                              NotifierTest
    ●   Faster tests (Y may be slow)
    ●   Simpler (Y may depend on Z etc)

●   Examples:                                IEmailSvc          Notifier
    ●   Time
    ●   Database
                                    EmailSvcStub   EmailSvc
    ●   Email
    ●   HttpContext
Stubs
●   Hand crafted

●   More effort to write

●   Easier to maintain

●   Can be more "black box" than mocks
Mocks
●   Mocks are automatically generated stubs

●   Easy to use

●   More "magical"

●   More effort to maintain

●   Will be more "white-box" than stubs

●   Example frameworks:
    ●   Moq
    ●   NSubstitute
Stubs - example
                              public class EmailSvcStub : IEmailSvc
                              {
                                  public int NumberOfEmailsSent { get; set; }

                                  public void SendEmail()
                                  {
                                      ++NumberOfEmailsSent;
                                  }
                              }


 [Test]
 public void Trigger()
 {
     // setup
     var emailSvc = new EmailSvcStub();
     var notifier = new Notifier(emailSvc);

     // invoke
     notifier.Trigger();

     // verify
     Assert.That(emailSvc.NumberOfEmailsSent, Is.EqualTo(1));
 }
Mocks - example




 [Test]
 public void Trigger()
 {
     // setup
     var emailSvc = Substitute.For<IEmailSvc>();
     var notifier = new Notifier(emailSvc);

     // invoke
     notifier.Trigger();

     // verify
     emailSvc.Received(1).SendEmail();
 }
Test data
●   Each developer his/her own database

●   Standard test data
    ●   Created before running tests

●   Test data builders
    ●   Stubbed database
    ●   Real database
Test data builder - example
[Test]
public void GetResponseMedia()
{
    // given
    var stub = new StubBuilder
    {
        Questions = new [] {
            new QuestionBuilder { Name = "MEDIA" },
        },
        Participants = new[] {
            new ParticipantBuilder { Name = "Lars", Votes = new [] {
                new VoteBuilder { Question = "MEDIA", Responses =
                    new ResponseBuilder(new byte [] {1, 2, 3}) },
            }},
        },
    }.Build();
    var voteController = new VoteController(stub.Session);

     // when
     var result = voteController.GetResponseMedia(vote.Id, true) as MediaResult;

     // then
     Assert.That(result.Download, Is.True);
     Assert.That(result.MediaLength, Is.EqualTo(3));
     Assert.That(TfResponse.ReadAllBytes(result.MediaStream), Is.EqualTo(new byte[] {1, 2, 3}));
}
Web UI testing
●   Control a browser from the tests using a seperate tool

●   Tools
    ●   Selenium
    ●   WatiN
    ●   Cucumber + capybara

●   Minimize system level testing
    ●   Web UI tests are brittle and slow
    ●   Hard to integrate into continuous integration

●   Maximize JavaScript unit testing
SQL testing
●   Test stored procedure, constraints, functions and triggers

●   Use your backend testing framework (like NUnit)
    ●   Easy to integrate in your Continuous Integration process

●   Consider using a dedicated framework

●   Or write your own
JavaScript testing
●   Use a JavaScript unit testing framework
    ●   QUnit
    ●   jsTestDriver
    ●   Jasmine
Web Service testing
●    Use your backend testing framework (like NUnit)

●    Use a JSON friendly version of WebClient:
    // when
    var votes = jsonClient.Get("Vote", "GetVotes", new { questionId = questionId });

    // then
    Assert.That(votes.Length, Is.EqualTo(1));
    var vote = votes[0];
    Assert.That(vote.ResponseText, Is.EqualTo("3"));
    Assert.That(vote.ParticipantName, Is.EqualTo("Lars Thorup"));


●    Input converted from .NET anonymous type to JSON

●    Output converted from JSON to .NET dynamic type

●    https://github.com/larsthorup/JsonClient
Legacy code
●   Add pinning tests
    ●   special kinds of unit tests for legacy
        code
    ●   verifies existing behaviour
    ●   acts as a safety net

●   Can be driven by change requests

●   Refactor the code to be able to write
    unit tests

●   Add unit test for the change request

●   Track coverage trend for existing
    code
    ●   and make sure it grows

More Related Content

Test and Behaviour Driven Development (TDD/BDD)

  • 1. Test & Behaviour Driven Development Lars Thorup ZeaLake Software Consulting March, 2012
  • 2. Who is Lars Thorup? ● Software developer/architect ● C++, C# and JavaScript ● Test Driven Development ● Coach: Teaching agile and automated testing ● Advisor: Assesses software projects and companies ● Founder and CEO of BestBrains and ZeaLake
  • 3. Why are we here today? ● What is TDD/BDD? ● Express expected behaviour before writing code ● Why is TDD/BDD a good thing? ● Enjoy more efficient and predictable course of development ● Find and fix bugs faster ● Prevent bugs from reappearing ● Improve the design of our software ● Reliable documentation ● How do we do TDD/BDD? ● Write test programs ● Run the tests automatically
  • 4. Workflow of TDD/BDD Think, talk Idea Test Failing test Code Good Succeeding design Refactor test
  • 5. BDD or TDD? ● Behaviour first ● makes more sense than "Test first" ● Structure of test programs ● Given <precondition> ● When <invocation> ● Then <expectation> ● High level as well as low level ● Testing user stories and requirements ● Testing class design and algorithms ● Communicate intent ● Fast feedback
  • 6. Different kinds of automated tests ● Unit tests ● Test individual pieces of code and the interaction between code blocks ● System tests / acceptance tests ● Verify the behaviour of the entire system against the requirements ● Performance tests ● Test non functional requirements
  • 7. Unit tests or system tests? ● Unit tests are efficient ● Fast to run (hundreds per second) ● Robust and predictable ● Can be easy to write ● Is written together with the code it is testing ● System tests are thorough ● Tests all layers together ● Most efficient way to create a set of tests for existing code ● Can be easier to read for non-technical people
  • 8. Can we automate performance tests? ● Performance tests are brittle ● Tip: create performance trend curves instead
  • 9. How do we run the tests automatically? ● From our programming environment (IDE) ● Command line: make test ● Right click | Run Tests ● On every commit ● Setup a build server ● Jenkins, TeamCity ● Let the build server run all tests ● Get build notifications ● Keep the build green ● Fixing a broken build has priority over any other development task
  • 10. How can tests help improve our design? ● The software design will evolve over time ● A refactoring improves the design without changing behavior ● Tests ensure that behavior is not accidentally changed ● Without tests, refactoring is scary ● and with no refactoring, the design decays over time ● With tests, we have the courage to refactor ● so we continually keep our design healthy
  • 11. Are we wasting developer time writing tests? ● No ● Time spent writing tests is not taken from time spent coding ● ... but from time otherwise spent on manual testing and debugging ● The cost of a bug keeps increasing until we fix it ● Find bugs faster ● Avoid losing customer confidence ● Free QA to do exploratory testing so they find the hard-to-find bugs ● Spend less time trying to figure out what is causing the bug and how to fix it ● Avoid spending time testing again
  • 12. How do we get started? ● When we have a lot of existing code without tests ● Create a set of system tests to get a safety net ● When we are writing new code ● Write unit tests in conjunction with the new code ● Set up a standard test environment for our specific application ● Test data: Automate the creation of standard testdata in a local database ● External dependencies: Write stubs to use in the tests
  • 13. Maintainability ● Stick to a pattern for your tests ● E.g. Given-When-Then ● Focus on readability over code duplication in test code ● Write reusable helper classes (builders) to simplify tests
  • 14. What does a real-world project look like? ● wizerize.com ● Web application: C# and JavaScript ● 3½ years of development, 3½ years in production ● 2-4 developers ● 40% test code, 60% production code (in lines of code) ● 71% code coverage of unit tests ● 872 unit tests – run in 1½ minute ● 72 system tests – run in 20 minutes ● No functional errors seen by end users in production (yet)
  • 15. Where can I read more? ● http://googletesting.blogspot.com/ ● http://testdrivendeveloper.com/ ● http://codesheriff.blogspot.com/ ● http://www.zealake.com/category/test/
  • 16. But what about: ● Stubs & mocks ● Test data ● UI testing ● SQL testing ● JavaScript testing ● Web Service testing ● Legacy code
  • 17. What is good design? ● One element of good design is loose coupling ● Use interfaces (for static languages) ● Inject dependencies public void Trigger() ● Avoid using new: { var emailSvc = new EmailSvc(); emailSvc.SendEmail(); } ● Inject dependencies instead: private IEmailSvc emailSvc; public Notifier(IEmailSvc emailSvc) { this.emailSvc = emailSvc; } public void Trigger() { emailSvc.SendEmail();
  • 18. Stubs and mocks ● When testing an object X, that depends on an object Y ● replace the real Y with a fake Y ● Benefits ● Only test one thing (X) at a time NotifierTest ● Faster tests (Y may be slow) ● Simpler (Y may depend on Z etc) ● Examples: IEmailSvc Notifier ● Time ● Database EmailSvcStub EmailSvc ● Email ● HttpContext
  • 19. Stubs ● Hand crafted ● More effort to write ● Easier to maintain ● Can be more "black box" than mocks
  • 20. Mocks ● Mocks are automatically generated stubs ● Easy to use ● More "magical" ● More effort to maintain ● Will be more "white-box" than stubs ● Example frameworks: ● Moq ● NSubstitute
  • 21. Stubs - example public class EmailSvcStub : IEmailSvc { public int NumberOfEmailsSent { get; set; } public void SendEmail() { ++NumberOfEmailsSent; } } [Test] public void Trigger() { // setup var emailSvc = new EmailSvcStub(); var notifier = new Notifier(emailSvc); // invoke notifier.Trigger(); // verify Assert.That(emailSvc.NumberOfEmailsSent, Is.EqualTo(1)); }
  • 22. Mocks - example [Test] public void Trigger() { // setup var emailSvc = Substitute.For<IEmailSvc>(); var notifier = new Notifier(emailSvc); // invoke notifier.Trigger(); // verify emailSvc.Received(1).SendEmail(); }
  • 23. Test data ● Each developer his/her own database ● Standard test data ● Created before running tests ● Test data builders ● Stubbed database ● Real database
  • 24. Test data builder - example [Test] public void GetResponseMedia() { // given var stub = new StubBuilder { Questions = new [] { new QuestionBuilder { Name = "MEDIA" }, }, Participants = new[] { new ParticipantBuilder { Name = "Lars", Votes = new [] { new VoteBuilder { Question = "MEDIA", Responses = new ResponseBuilder(new byte [] {1, 2, 3}) }, }}, }, }.Build(); var voteController = new VoteController(stub.Session); // when var result = voteController.GetResponseMedia(vote.Id, true) as MediaResult; // then Assert.That(result.Download, Is.True); Assert.That(result.MediaLength, Is.EqualTo(3)); Assert.That(TfResponse.ReadAllBytes(result.MediaStream), Is.EqualTo(new byte[] {1, 2, 3})); }
  • 25. Web UI testing ● Control a browser from the tests using a seperate tool ● Tools ● Selenium ● WatiN ● Cucumber + capybara ● Minimize system level testing ● Web UI tests are brittle and slow ● Hard to integrate into continuous integration ● Maximize JavaScript unit testing
  • 26. SQL testing ● Test stored procedure, constraints, functions and triggers ● Use your backend testing framework (like NUnit) ● Easy to integrate in your Continuous Integration process ● Consider using a dedicated framework ● Or write your own
  • 27. JavaScript testing ● Use a JavaScript unit testing framework ● QUnit ● jsTestDriver ● Jasmine
  • 28. Web Service testing ● Use your backend testing framework (like NUnit) ● Use a JSON friendly version of WebClient: // when var votes = jsonClient.Get("Vote", "GetVotes", new { questionId = questionId }); // then Assert.That(votes.Length, Is.EqualTo(1)); var vote = votes[0]; Assert.That(vote.ResponseText, Is.EqualTo("3")); Assert.That(vote.ParticipantName, Is.EqualTo("Lars Thorup")); ● Input converted from .NET anonymous type to JSON ● Output converted from JSON to .NET dynamic type ● https://github.com/larsthorup/JsonClient
  • 29. Legacy code ● Add pinning tests ● special kinds of unit tests for legacy code ● verifies existing behaviour ● acts as a safety net ● Can be driven by change requests ● Refactor the code to be able to write unit tests ● Add unit test for the change request ● Track coverage trend for existing code ● and make sure it grows