Roy Osherove on Unit Testing Good Practices and Horrible Mistakes

Preview:

Citation preview

Unit Testing Good Practices & Horrible Mistakes

@RoyOsherove

What I do (artOfUnitTesting.com)

Courses on TDD, BDD in JS, Ruby, Java and C# TDD (EpiServer TDD, MVC TDD…)Courses for Team Leaders (5whys.com)Consulting & coaching through Bouvet

Contact.osherove.com

Team Agile - All rights reserved

Real World Agenda

Test Reviews

Making your tests TRUSTworthyCreating MAINTAINable testsREADable tests

RTFM

Test review vs. code review

Understand intent of developer10 times quickerDrill in when needed

Important for learning teamsHelps drive change

Maintainable

Trustworthy

Readable

Make Your tests trust worthy

Make it easy to runRemoving or changing testsAssuring code coverageAvoid test logic Avoid Manual Stub\Mock LogicDon’t Repeat Production Logic

Separate Unit From Integration Tests

Code coverage?

Worthless without a code reviewChange production code and see what happens

Make params into constsRemove “if” checks – or make into consts

If all tests pass - something is missing or something is not needed

Avoid test logic (MS Unity)

Another logic example:MVCDev.HtmlHelperTest.GetHttpContext()

Don’t repeat production logic

String user = “a”;String password= “b”;

String SomeResult = UnderTest.CreateMessage(user,password);

Assert.AreEqual( user + “,” + password,

SomeResult);

Don't use things that keep changing

DateTime.NowRandomEnvironment.TickCountThreadsEtc..

Tests that keep changing: NerdDinner

Creating maintainable tests

Avoid testing private/protected membersRe-use test code (Create, Manipulate, Assert)Enforce test isolationTest One Thing

Avoid Multiple AssertsOne mock per test

Use “relaxed” or “Non strict” mocks and stubs

Test only publics

“Unit” testing == “Unit Of Work Testing”Testing a private makes your test more brittleMakes you think about the design and usability of a featureTest-First leads to private members after Refactoring, but they are all tested!

But sometimes there’s not choice

Reuse test code

Create objects using common methods (factories)

[make_XX]Manipulate and configure initial state using common methods

[init_XX]Run common tests in common methods

[verify_XX]

Enforce test isolation

No dependency between tests!Don’t run a test from another test!Run alone or all together in any orderOtherwise – leads to nasty “what was that?” bugs

Avoid Multiple Asserts On different objects

String user = “a”;String password= “b”;

String SomeResult = UnderTest.CreateMessage(user,password);

Assert.AreEqual( user + “,” + password, SomeResult);

Assert.AreEqual (1,UnderTest.MessageCount);

Avoid Multiple AssertsMVCDev.LinkExtensionsTest L. 334

Avoid Multiple Asserts

Like having multiple testsBut the first the fails – kills the othersYou won’t get the big picture (some symptoms)Hard to nameCan lead to more debugging work

Avoid Multiple Mocks

Creating readable tests

StructureNo Magic values

In testIn mock\stub

Naming a unit testNaming variablesSeparate Assert from action

Structure

Are the tests easy to find?Can you find a test for a class, or a method?

Setup Mystery

Bad Naming

No Magic Values

Assert.AreEqual(1003, calc.Parse(“-1”));

Int parseResult = calc.Parse(NEGATIVE_ILLEGAL_NUMBER);

Assert.AreEqual(NEGATIVE_PARSE_RETURN_CODE, parseResult)

Hidden Values

Magic values in Fakes

Magic ValuesUnity InjectionMethodFixture

Call it what it is (mock\stub\fake)

Most “Mocks” are actually stubs.If it can be both, call it “Fake”

Naming a unit test

Method nameState under testExpected behavior/return value

Add_LessThanZero_ThrowsException()Another angle:Add_LessThanZero_ThrowsException2()

Naming

Separate Assert from Action

Assert is less clutteredMore readableAllows handling the return value if neededIt’s all about readability

Input Values Should Differ

X.Divide (1,1)X.Divide (1,2)

X.Check(“1,1”)X.Check(“1,2”)

Maintainable

Trustworthy

Readable

ArtOfUnitTesting.com

Song?

This is a test line

Looks like you’re doing fine

Time for a song of mine

Hello DB My Old Friend

Hellow DB my old friend

I need to work with you again

That stored procedure ain’t working wellWhoever wrote that trigger should go to jail

And that index , it is slower than a snailWhat the hell? I guess it’s time…

FOR VIOLENCE

Man, whoever wrote this codeThat bastard’s gonna hit the road

Now the customer is gonna sueInstead of red, my face is turning blue

And it seems like there is no way out of this.

There’s just a hiss.

I guess it’s time, for violence..

I’m angry and I want a name

That DBA should be ashamed

What’s that you’re saying?It’s ME to blame?

That database was my own sick game?

Oh that’s right.It was me who did the design

It was mine.I guess it’s time…

FOR SILENCE.

Thank You

royo@bouvet.no

Coaching, mentoring and trainingFor team leaders, developers, architects and product owners