delivering on tdd - meetupfiles.meetup.com › 3647052 › delivering on tdd (bsug).pdf ·...

109
Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t do that!” Or Note to self: if it hurts, I’m doing it wrong Or The unit tests are dead, long live the unit tests!

Upload: others

Post on 27-Jun-2020

9 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Delivering on TDDOr

Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t do that!”

Or 

Note to self: if it hurts, I’m doing it wrong

OrThe unit tests are dead, long live the unit

tests!

Page 2: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Before we get into it…

• I’m speaking only for myself, not for my company

• I’m not promoting a book • I’m just the guy that

spends every working day typing in the tests and the code

Page 3: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

The risk (for you)

This presentation may upset

Page 4: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

The risk (for me)

Well, duh!

Page 5: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Background My light bulb moment

Techniques

Going forwards…

Exemplum

Page 6: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Who he?

• I am Paul Scully • Previous life (10 or so bitter years) as a

games developer, primarily C/C++ • Joined Renishaw in January 2007 – Started as a C++ developer working with

machine tools – Changed role at the start of 2011, as a C#

developer in the healthcare division

Page 7: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

My story: TDD vs Happiness

Page 8: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

What do I do?• neuro|inspire - a desktop application for

neurological surgery planning for example in the treatment of Parkinson’s disease

• Delivery of electrodes via a stereotactic arc mounted on a frame bolted to the patient’s head

• Software calculates values “dialled into” the arc

Page 9: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Eye candy

Page 10: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

The team, the architecture

• The first team in the company to adopt an agile process – TDD, mocking frameworks, pair programming,

sprints… – All those good things

• C# • Model-View-Presenter architecture • Passive view

Page 11: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

My experience of TDD

• We TDD-ed 100% of the code • I learnt TDD on the job • A year on, I was still learning how to TDD • But not in a good way – Something wasn’t gelling – Ducks were not in a row – Happiness was decreasing

Page 12: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

My story: Nosedive karma

Page 13: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Unhappy?

• I saw and participated in “interesting” coding acts when writing tests

Page 14: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Unhappy?

• I saw and participated in “interesting” coding acts when writing tests – Private accessor classes – Generated by VisualStudio

…MSBuild\Microsoft\VisualStudio\v11.0\TeamTest\Microsoft.TeamTest.targets(14,5): warning : This task to create private accessor is deprecated and will be removed in a future version of visual studio.

Page 15: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Unhappy?

• I saw and participated in “interesting” coding acts when writing tests – Test classes with state

[TestClass]public class When_BurnCD_Method_Called{ IProgressReporterModel _progressReportModel; IProgressReporterView _progressReportView; IBurnMedia _burnMedia; MsftDiscMaster2 _discMaster; MsftDiscFormat2Data _discFormatData;

Page 16: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Unhappy?

• I saw and participated in “interesting” coding acts when writing tests – Test classes derived from other test classes

[TestClass]public class When_selected_series_changed_fired_on_view : Using_simple_setup{}

Page 17: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Unhappy?

• I saw and participated in “interesting” coding acts when writing tests – “Testable” classes derived from real classes

internal class Implementation{ protected void SomeMethodThatShouldBePrivate() { /* Code */ }

internal class TestableImplementation : Implementation{ public void CallSomeMethodThatShouldBePrivate() { base.SomeMethodThatShouldBePrivate(); }}

Page 18: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Unhappy?

• I saw and participated in “interesting” coding acts when writing tests – “Testable” classes derived from real classes

internal class Implementation{ protected void SomeMethodThatShouldBePrivate() { /* Code */ }

internal class TestableImplementation : Implementation{ public void CallSomeMethodThatShouldBePrivate() { base.SomeMethodThatShouldBePrivate(); }}

Page 19: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

The horror!

“I've increasingly come to believe that unit tests are so important that they should be a first-class language construct.” (Jeff Atwood, 2006)

Page 20: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Unhappy?

• 75% of the code in a test was set-up • Writing a test seemed mostly about

setting up faked collaborators – Return values –When method x is called, return value of

property y changes to z –When p is called, event q is raised

Page 21: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Set-up!

• There’s more to set-up than when writing a test - you have to maintain set-up

• Exemplum – refactoring of a class… – When no results return null instead of empty list – Red-Green-Refactor the change – Run all tests: they pass – Run the application… Crash!?!

• You must maintain the behaviour of the mocks otherwise your tests move to la-la-land – In a complex system, that’s a lot of maintenance

Page 22: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

What is a TDD test, anyway?

• “Unit test” means “test a unit of code”… • And TDD means unit tests… • Then I test one real class instance… • Therefore everything else must be fake… • But fakes mean... • Set-up! • What do fakes mean? Set-up!

Page 23: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

How I Think I (and the Code) Got There

• We all were learning: me, and those teammates teaching me how to do TDD

• And that goes for the authors of much of the material I'd read on the internet, too

Page 24: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

What’s in a name?Should_call_draw_for_OverlaySeries_on_feature_renderer_if_overlay_series_displayed

ModelEvents_FrameArcOrientationChangedWithFramePresentAndFitted_ShouldUpdateViewFrameStatusTextCorrectly

CalculateOrientationMatrix_withValidTrajectory_ReturnsRotationMatrix

• Too much information? • Not enough information?

Page 25: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Implementing Implementation Tests

• A correspondence between a test and a method of the unit-under-test…

• …leads to tests tied to implementation • Not such a problem when writing the tests… but

a nightmare when refactoring! – So, which tests to change, which to delete, which to

keep?

Page 26: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

The Long-term Negatives Outweighed the Short-term Positives 

• TDD was not helping me to write maintainable code, nor helping me to maintain code

• I’d always seen the tests as my safety net

Page 27: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

My story: Rock bottom

Page 28: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

My story: Something interesting is about to happen…

Page 29: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

• A version of neuro|inspire manufactured to an NHS Trust’s specification – Used in trialling new techniques, technologies

and treatments, especially the delivery of drugs directly into the brain to circumvent the blood-brain barrier

– Delivery using the neuro|mate stereotactic robot

– As seen on TV!

neuro|inspire for Drug Delivery

Page 30: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

• TDD given less prominence than code turn-around

• Testing would be manual, script-based • With a leap and a bound, I was free from

the pain of TDD!

Freedom!

Page 31: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

My story: Everything’s groovy!

Page 32: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

So far, so good

• For a while, this was great – Time to deliver features was short – Refactoring, unimpeded by unit test

maintenance(!), was quick and easy – Defect rate for new functionality was very low

• But, manual testing was an ever growing burden – More features mean more manual tests – More manual tests mean more time testing – More time testing means… fewer weekends

Page 33: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

So far, so good

Page 34: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

My story: This can’t go on

Page 35: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

My “Light Bulb” Moment

Page 36: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Ian Cooper to the Rescue!

• Ian Cooper’s presentation “TDD, where did it all go wrong?”

• http://vimeo.com/68375232 • Two “takeaways” that changed profoundly

my understanding of TDD 1. The test is the unit 2. Don’t fake in the domain

• All this time... had I been doing it wrong?

Page 37: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

The test is the unit

• A test is isolated • A test does not require any other test to

first be run • No state carried from a test to any

following test • That’s it?! • The test is the unit, not the code under

test

Page 38: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Let’s look again at that chain of logic…

• “Unit test” means “test a unit of code”… Hang on, it doesn’t have to!

• And TDD means unit tests… It’s TDD, not UTDD

• Then I test one real class instance… • Therefore everything else must be fake… Who says so? Maybe it was Beck?

Page 39: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Maybe it was Beck?

• “Who, me? Nope”

Page 40: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

• Still “Nope”

Maybe it was Beck?

Page 41: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Beck in full flow…

Page 42: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Beck in full flow…

public void testMixedAddition() { Expression fiveBucks= Money.dollar(5); Expression tenFrancs= Money.franc(10); Bank bank= new Bank(); bank.addRate("CHF", "USD", 2); Money result= bank.reduce(fiveBucks.plus (tenFrancs), "USD"); assertEquals(Money.dollar(10), result); }

Page 43: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Beck in full flow…

public void testMixedAddition() { Expression fiveBucks= Money.dollar(5); Expression tenFrancs= Money.franc(10); Bank bank= new Bank(); bank.addRate("CHF", "USD", 2); Money result= bank.reduce(fiveBucks.plus (tenFrancs), "USD"); assertEquals(Money.dollar(10), result); }

Page 44: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Don’t fake in the domain

Domain

real class instance

real class instance

real class instance

UI

Robot

Data

Page 45: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Test

Don’t fake in the domain

Domain

real class instance

real class instance

real class instance

Fake UI

Fake Robot

Fake Data

Page 46: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Test

Don’t fake in the domain

Domain

real class instance

real class instance

real class instance

Fake UI

Fake Robot

Fake Data

Page 47: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Test

Don’t fake in the domain

Domain

real class instance

real class instance

real class instanceFake Robot

Fake Data

Fake UI

Page 48: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Test

Don’t fake in the domain

Fake UI

Fake Robot

Fake Data

Domain

real class instance

real class instance

real class instance

Page 49: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Test

Don’t fake in the domain

Fake UI

Fake Robot

Fake Data

Domain

real class instance

real class instance

real class instance

Page 50: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

And breathe…

Page 51: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

What Do I Want From My Tests?

1. Describe required behaviour 2. Tell me if I’ve broken any behaviour 3. Be maintainable

Page 52: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Techniques I Use

1. Think “requirements” first 2. Describe the required behaviour 3. Isolate the tests 4. Test real objects and real collaborations 5. Test boundary to boundary 6. Don’t be afraid to check in failing tests 7. Red-Green-Refactor really works!

Page 53: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Think “Requirements” First• Use whatever methods you as an

individual/pair/team find work for you • For me, that’s two things: whiteboards, and

talking to the customer (representative)

Page 54: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Describe the Required Behaviour

• I write one, two, (ten, thirty) empty tests describing the behaviour I am about to implement

• Test names use a Given-When-Then from the PoV of the user

GivenTheUserCanBing_WhenTheUserBings_ThenTheUserCanBongGivenTheUserCanBong_WhenTheUserBongs_ThenTheUserCanBang

• Empty except for Assert.Fail()

Page 55: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Isolate the tests

• Each of my test classes contains a “TestEnvironment” class – More on this later

• Created by a test, used in that test, and dies along with the test

Page 56: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Test Real Objects and Real Collaborations

• Instance factories are the real factories, creating real instances, except for...

• UI factory, renderer factory, I/O factory – The WinForms views are fake – The DirectX renderers are fake – File I/O is fake – The lowest level of the robot is fake

• The real builder classes are used

Page 57: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Test Boundary to Boundary

• Boundary: where it becomes pointless, impractical or impossible to use real instances

• FakeView ! real instances ! FakeView • FakeView ! real instances ! FakeIO • FakeView ! real instances ! FakeRobot • FakeRobot ! real instances ! FakeView

Page 58: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Don’t Be Afraid To Check In Failing Tests

• Make the first test pass • But you still have all those Assert.Fail()

• Check in? Yes! You have value sitting in your changes

• Never check in failing tests you don’t expect to fail

• If you broke something, find out why, and fix it!

Page 59: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Red-Green-Refactor really works!

• When refactoring doesn’t change a line of test code...

• And tests fail only because something got broke…

• Test sweet! • My pair and I have often produced

alternative but equivalent implementations, discussed their relative merits and decided on the best approach within the R-G-R cycle

Page 60: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Patient: “Doctor, when I do this, it hurts.”

Doctor: “Then don’t do that!” • Losing the pain from TDD has been

liberating

Page 61: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Note to self: if it hurts, I’m doing it wrong

• The pain was caused by – Tests tied to implementation – Set-up of fake collaborators

• The pain went away when – I started testing behaviour – I used real objects – I faked only outside the domain

Page 62: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

The unit tests are dead, long live the unit tests!

• I love writing tests! • Easy to write • Easy to read • Easy to change

• TDD - 100% • Premier League levels of happiness - 110%

Page 63: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

My story: Premier League Happiness

Page 64: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Questions so far?

Page 65: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

I have some…

• What does a TestEnvironment class look like?

• What does a unit test look like? • How does my R-G-R cycle progress? • How does the TestEnvironment change?

Page 66: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

A TestEnvironment

• Isolated: a new instance per test • Reusable: one serves many tests • Descriptive: fluent interface phrased in

terms of user activities • Extendable: grows as the tests are written • Low maintenance: changes almost always

additions, not rewrites or fixes

Page 67: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

[TestClass]public class UnitTests{ [TestMethod] public void GivenTheUserCanBing_WhenTheUserBings_TheUserCanBong() { Assert.Fail(); }

[TestMethod] public void GivenTheUserCanBong_WhenTheUserBongs_TheUserCanBang() { Assert.Fail(); }

[TestMethod] public void GivenTheUserCanBang_WhenTheUserBangs_TheUserCanBoing() { Assert.Fail(); }}

Page 68: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

[TestClass]public class UnitTests{ [TestMethod] public void GivenTheUserCanBing_WhenTheUserBings_TheUserCanBong() { Assert.Fail(); }

[TestMethod] public void GivenTheUserCanBong_WhenTheUserBongs_TheUserCanBang() { Assert.Fail(); }

[TestMethod] public void GivenTheUserCanBang_WhenTheUserBangs_TheUserCanBoing() { Assert.Fail(); }}

Page 69: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

[TestMethod]public void GivenTheUserCanBing_WhenTheUserBings_TheUserCanBong(){ // Arrange var testEnvironment = new TestEnvironment();

// Act testEnvironment.TheUserBings();

// Assert testEnvironment.View.Received().EnableBong();}

Page 70: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

[TestMethod]public void GivenTheUserCanBing_WhenTheUserBings_TheUserCanBong(){ // Arrange var testEnvironment = new TestEnvironment();

// Act testEnvironment.TheUserBings();

// Assert testEnvironment.View.Received().EnableBong();}

Page 71: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

private class TestEnvironment{ public TestEnvironment() { View = Substitute.For<IView>(); var viewFactory = Substitute.For<IViewFactory>(); viewFactory.CreateView().Returns(View);

TheApplicationBuilder.CreateApplication(viewFactory); }

public IView View { get; private set; }}

Page 72: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

private class TestEnvironment{ public TestEnvironment() { View = Substitute.For<IView>(); var viewFactory = Substitute.For<IViewFactory>(); viewFactory.CreateView().Returns(View);

TheApplicationBuilder.CreateApplication(viewFactory); }

public IView View { get; private set; }}

Page 73: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

private class TestEnvironment{ public TestEnvironment() { View = Substitute.For<IView>(); var viewFactory = Substitute.For<IViewFactory>(); viewFactory.CreateView().Returns(View);

TheApplicationBuilder.CreateApplication(viewFactory); }

public IView View { get; private set; }}

Page 74: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

private class TestEnvironment{ public TestEnvironment() { View = Substitute.For<IView>(); var viewFactory = Substitute.For<IViewFactory>(); viewFactory.CreateView().Returns(View);

TheApplicationBuilder.CreateApplication(viewFactory); }

public IView View { get; private set; }}

Page 75: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

private class TestEnvironment{ public TestEnvironment() { View = Substitute.For<IView>(); var viewFactory = Substitute.For<IViewFactory>(); viewFactory.CreateView().Returns(View);

TheApplicationBuilder.CreateApplication(viewFactory); }

public IView View { get; private set; }}

Page 76: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

[TestMethod]public void GivenTheUserCanBing_WhenTheUserBings_TheUserCanBong(){ // Arrange var testEnvironment = new TestEnvironment();

// Act testEnvironment.TheUserBings();

// Assert testEnvironment.View.Received().EnableBong();}

Page 77: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

private class TestEnvironment{ public TestEnvironment() { View = Substitute.For<IView>(); var viewFactory = Substitute.For<IViewFactory>(); viewFactory.CreateView().Returns(View);

TheApplicationBuilder.CreateApplication(viewFactory); }

public IView View { get; private set; }

public TestEnvironment TheUserBings() { View.BingRequested += Raise.Event();

return this; }}

Page 78: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

[TestMethod]public void GivenTheUserCanBing_WhenTheUserBings_TheUserCanBong(){ // Arrange var testEnvironment = new TestEnvironment();

// Act testEnvironment.TheUserBings();

// Assert testEnvironment.View.Received().EnableBong();}

Page 79: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Fail!

Page 80: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Run test – Red Code… Run test – Red Code… Run test – Green Run all tests – Green, (Red, Red) Refactor… Run all tests – Red, (Red, Red) ! Fix… Run all tests – Green, (Red, Red)

Page 81: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

[TestMethod]public void GivenTheUserCanBong_WhenTheUserBongs_TheUserCanBang(){

Assert.Fail();}

Page 82: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

[TestMethod]public void GivenTheUserCanBong_WhenTheUserBongs_TheUserCanBang(){ // Arrange var testEnvironment = new TestEnvironment();

// Act testEnvironment.TheUserBings();

// Assert testEnvironment.View.Received().EnableBong();}

Page 83: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

[TestMethod]public void GivenTheUserCanBong_WhenTheUserBongs_TheUserCanBang(){ // Arrange var testEnvironment = new TestEnvironment()

// Act testEnvironment

// Assert testEnvironment.View.Received().EnableBong();}

.TheUserBings();

Page 84: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

[TestMethod]public void GivenTheUserCanBong_WhenTheUserBongs_TheUserCanBang(){ // Arrange var testEnvironment = new TestEnvironment() .TheUserBings();

// Act testEnvironment

// Assert testEnvironment.View.Received().EnableBong();}

Page 85: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

[TestMethod]public void GivenTheUserCanBong_WhenTheUserBongs_TheUserCanBang(){ // Arrange var testEnvironment = new TestEnvironment() .TheUserBings();

// Act testEnvironment.TheUserBongs();

// Assert testEnvironment.View.Received().EnableBang();}

Page 86: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

private class TestEnvironment{ public TestEnvironment() { … }

public TestEnvironment TheUserBings() { View.BingRequested += Raise.Event();

return this; }

public TestEnvironment TheUserBongs() { View.BongRequested += Raise.Event();

return this; }}

Page 87: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Run test – Red Code… Run test – Green Run all tests – Green, Green, (Red) Refactor… Run all tests – Red, Green, (Red) !!! Fix… Run test – Green Run all tests – Green, Green, (Red)

Page 88: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

[TestMethod]public void GivenTheUserCanBang_WhenTheUserBangs_TheUserCanBoing(){ Assert.Fail();}

Page 89: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

[TestMethod]public void GivenTheUserCanBang_WhenTheUserBangs_TheUserCanBoing(){ // Arrange var testEnvironment = new TestEnvironment() .TheUserBings();

// Act testEnvironment.TheUserBongs();

// Assert testEnvironment.View.Received().EnableBong();}

Page 90: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

[TestMethod]public void GivenTheUserCanBang_WhenTheUserBangs_TheUserCanBoing(){ // Arrange var testEnvironment = new TestEnvironment() .TheUserBings()

// Act testEnvironment.TheUserBongs();

// Assert testEnvironment.View.Received().EnableBong();}

Page 91: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

[TestMethod]public void GivenTheUserCanBang_WhenTheUserBangs_TheUserCanBoing(){ // Arrange var testEnvironment = new TestEnvironment() .TheUserBings()

// Act testEnvironment

// Assert testEnvironment.View.Received().EnableBong();}

.TheUserBongs();

Page 92: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

[TestMethod]public void GivenTheUserCanBang_WhenTheUserBangs_TheUserCanBoing(){ // Arrange var testEnvironment = new TestEnvironment() .TheUserBings() .TheUserBongs();

// Act testEnvironment.TheUserBangs();

// Assert testEnvironment.View.Received().EnableBoing();}

Page 93: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

How to train your TestEnvironment

• As each test is written, “acts” migrate to the “arrange” phase of following tests

• Power is added to the TestEnvironment, test by test

• But, not via any set-up code! • Sequences of acts can be consolidated

into a “meta arrange”

Page 94: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

[TestMethod]public void GivenTheUserCanBoing_WhenTheUserBoings_TheUserCan…(){ // Arrange var testEnvironment = new TestEnvironment() .TheUserBings() .TheUserBongs() .TheUserBangs();

// Act testEnvironment…

// Assert testEnvironment…}

Page 95: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

private class TestEnvironment{ …

public TestEnvironment TheUserBingsBongsBangs() { return this .TheUserBings() .TheUserBongs() .TheUserBangs(); }}

Page 96: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

[TestMethod]public void GivenTheUserCanBoing_WhenTheUserBoings_TheUserCan(){ // Arrange var testEnvironment = new TestEnvironment() .TheUserBingsBongsBangs();

// Act testEnvironment…

// Assert testEnvironment…}

Page 97: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

[TestMethod]public void GivenTheUserCanBoing_WhenTheUserBoings_TheUserCan…(){ // Arrange var testEnvironment = new TestEnvironment() .TheUserBingsBongsBangs();

// Act testEnvironment…

// Assert testEnvironment…}

Page 98: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

private class TestEnvironment{ …

public TestEnvironment TheUserCanInsertACatheter() { return this .TheUserHasMovedTheRobotToPosition() .TheUserHasDrilledTheFeature() .TheUserHasPreparedTheCatheter(); }}

Page 99: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

private class TestEnvironment{ …

public TestEnvironment TheUserHasLoggedIn() { return this .TheUserEntersAUsername(“paul”) .TheUserEntersAMatchingPassword(“tddrox”) .TheUserLogsIn(); }}

Page 100: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Changing the requirements, huh?

• This happens all the flipping time

Page 101: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Done. Any more?

• When requirements change, it is easy to: • Identify the tests to be deleted • Identify the tests to be changed • Write the new tests for the new

behaviour • TDD 100%, happiness 110%

Page 102: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Questions?

[email protected] https://rightbettercode.wordpress.com/

(Renishaw are recruiting…)

Page 103: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

var testEnvironment = NewTestEnvironment()

.TheUserSelectsTrajectory(trajectoryName)

.TheUserSetsRenderPilotDrillTo(true)

.FinishArrange();

// Act

testEnvironment.TheUserSetsRenderPilotDrillTo(false);

// Assert

testEnvironment.Rendering.AssertThat.

AllViewsWereRedrawn().

And.ThePilotDrillWasNotRendered();

103

Page 104: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Where to begin

Three suggestions for you: 1. TDD a new application 2. Start small: take an existing test, move

the boundaries 3. Start big: start the application, quit the

application

Page 105: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

TDD a new application

• With your requirements ready – Grab a teammate - pair! – Create a new test class – Create a nested test environment

• Fake your UI • Inject the fake UI into the application builder

– R-G-R the requirements – Add descriptive tests – Add power to the test environment – Add value to the code

Page 106: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Take an existing test…

• Move outward the boundaries of the test – Look at the test set-up – Identify a fake that could be real – Make it real

• You will need to do something about its collaborators…

• Repeat until the only fakes are outside the domain

Page 107: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Start the application, quit the application

• This is where I started • Could I “start the application”? – Build up enough real objects – A fake UI

• So that when UI raised the “Quit” event – Was the “Dispose” method on the main UI window

called? • Then, could I do something more interesting? – Add a target? – Trigger a save? – Change into “Delivery” mode?

Page 108: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

Yes108

Page 109: Delivering on TDD - Meetupfiles.meetup.com › 3647052 › Delivering on TDD (BSUG).pdf · Delivering on TDD Or Patient: “Doctor, when I do this, it hurts.” Doctor: “Then don’t

No109