Download - Test and Behaviour Driven Development (TDD/BDD)

Transcript
Page 1: Test and Behaviour Driven Development (TDD/BDD)

Test & BehaviourDriven DevelopmentLars ThorupZeaLake Software Consulting

March, 2012

Page 2: Test and Behaviour Driven Development (TDD/BDD)

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

Page 3: Test and Behaviour Driven Development (TDD/BDD)

● 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

Why are we here today?

Page 4: Test and Behaviour Driven Development (TDD/BDD)

Workflow of TDD/BDD

Failingtest

Succeedingtest

Gooddesign Refactor

Code

Test

IdeaThink, talk

Page 5: Test and Behaviour Driven Development (TDD/BDD)

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

Page 6: Test and Behaviour Driven Development (TDD/BDD)

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

Page 7: Test and Behaviour Driven Development (TDD/BDD)

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

Page 8: Test and Behaviour Driven Development (TDD/BDD)

Can we automate performance tests?● Performance tests are brittle

● Tip: create performance trend curves instead

Page 9: Test and Behaviour Driven Development (TDD/BDD)

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

Page 10: Test and Behaviour Driven Development (TDD/BDD)

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

Page 11: Test and Behaviour Driven Development (TDD/BDD)

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

Page 12: Test and Behaviour Driven Development (TDD/BDD)

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

Page 13: Test and Behaviour Driven Development (TDD/BDD)

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

Page 14: Test and Behaviour Driven Development (TDD/BDD)

● 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)

What does a real-world project look like?

Page 15: Test and Behaviour Driven Development (TDD/BDD)

Where can I read more?● http://googletesting.blogspot.com/

● http://testdrivendeveloper.com/

● http://codesheriff.blogspot.com/

● http://www.zealake.com/category/test/

Page 16: Test and Behaviour Driven Development (TDD/BDD)

But what about:● Stubs & mocks

● Test data

● UI testing

● SQL testing

● JavaScript testing

● Web Service testing

● Legacy code

Page 17: Test and Behaviour Driven Development (TDD/BDD)

What is good design?● One element of good design is loose coupling

● Use interfaces (for static languages)● Inject dependencies

● Avoid using new:

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

public void Trigger(){ emailSvc.SendEmail();

public void Trigger(){ var emailSvc = new EmailSvc(); emailSvc.SendEmail();}

Page 18: Test and Behaviour Driven Development (TDD/BDD)

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● Faster tests (Y may be slow)● Simpler (Y may depend on Z etc)

● Examples:● Time● Database● Email● HttpContext

Notifier

EmailSvc

IEmailSvc

EmailSvcStub

NotifierTest

Page 19: Test and Behaviour Driven Development (TDD/BDD)

Stubs● Hand crafted

● More effort to write

● Easier to maintain

● Can be more "black box" than mocks

Page 20: Test and Behaviour Driven Development (TDD/BDD)

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

Page 21: Test and Behaviour Driven Development (TDD/BDD)

Stubs - examplepublic 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));}

Page 22: Test and Behaviour Driven Development (TDD/BDD)

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();}

Page 23: Test and Behaviour Driven Development (TDD/BDD)

Test data● Each developer his/her own database

● Standard test data● Created before running tests

● Test data builders● Stubbed database● Real database

Page 24: Test and Behaviour Driven Development (TDD/BDD)

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}));}

Page 25: Test and Behaviour Driven Development (TDD/BDD)

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

Page 26: Test and Behaviour Driven Development (TDD/BDD)

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

Page 27: Test and Behaviour Driven Development (TDD/BDD)

JavaScript testing● Use a JavaScript unit testing framework

● QUnit● jsTestDriver● Jasmine

Page 28: Test and Behaviour Driven Development (TDD/BDD)

Web Service testing● Use your backend testing framework (like NUnit)

● Use a JSON friendly version of WebClient:

● Input converted from .NET anonymous type to JSON

● Output converted from JSON to .NET dynamic type

● https://github.com/larsthorup/JsonClient

// whenvar votes = jsonClient.Get("Vote", "GetVotes", new { questionId = questionId });

// thenAssert.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"));

Page 29: Test and Behaviour Driven Development (TDD/BDD)

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