Unit tests = maintenance hell ?

35
Unit Tests = Maintenance Hell ? Thibaud DESODT @tsimbalar

description

The slides or my talk at SoftShake (soft-shake 2013) about unit test maintenance. The code can be found here : https://github.com/tsimbalar/UnitTestsMaintenanceHell Abstract (in French, sorry ...) : “Oui, les tests unitaires, c’est cool, mais à chaque fois que je fais une petite modification dans le code, je dois réparer tous mes tests, c’est pénible et ça me prend un temps fou! Alors j’hésite à laisser tomber ma suite de tests, ou alors je fais l’impasse sur ce refactoring …” Vous avez déjà entendu ça, non ? Quand on se met à écrire des tests unitaires (que ce soit avant ou après le code à tester), au début, c’est la galère, puis, peu à peu, avec l’habitude et l’expérience, on les écrit mieux et plus rapidement … mais quand il s’agit de modifier du code existant, on a quand même l’impression de se prendre les pieds dans les tests. Dans cette session, je vous présenterai quelques techniques, trucs et outils pour écrire des tests plus maintenables et vous sentir moins gênés lors des refactorings du code. Cette présentation se basera sur des exemples de code et des démos (en C# et avec Visual Studio) Les tests apportent une forte valeur ajoutée à nos projets, ce qu’il faut, c’est essayer d’en réduire le coût…

Transcript of Unit tests = maintenance hell ?

Page 1: Unit tests = maintenance hell ?

Unit Tests = Maintenance Hell ?

Thibaud DESODT@tsimbalar

Page 2: Unit tests = maintenance hell ?

This talk

• About Unit-Testing– Why we do it – Why it can slow you down– How to ease the maintenance

• Include : – .NET-based examples / tools– … can be applied to other platforms

Page 3: Unit tests = maintenance hell ?

UNIT TESTS

Page 4: Unit tests = maintenance hell ?

Value of Unit tests

Codebase size

Valu

e o

f Uni

t tes

ts

“toy” project

s

• Benefits– Avoid introducing bugs– Executable documentation– Regression detection– Know when to stop– Reduce fear / allow

refactoring– …

Unit-tests help build CONFIDENCE

Page 5: Unit tests = maintenance hell ?

But when the codebase grows …

Page 6: Unit tests = maintenance hell ?

Quantity of Test Code

• Prod Code vs Test Code Ratio– from 1:1 to 1:5 !

• Muliplied efforts :– New Code – Changing existing code

More Test Code than Prod Code !

Page 7: Unit tests = maintenance hell ?

Lower Quality of Test Code

• Viewed as less important than Prod Code– “Write Once” – Duplication / Copy+Paste– Less refactoring / improvements– Hard to read/understand

• Technical Debt reduction has less priority

Page 8: Unit tests = maintenance hell ?

Cost of Unit Tests

Codebase size

Cost

of U

nit t

ests

Unit-tests introduce FRICTION

Page 9: Unit tests = maintenance hell ?

ROI

Codebase size

Valu

e vs

Cos

t of

Uni

t tes

ts

WTF?

Page 10: Unit tests = maintenance hell ?

Unit Tests = Maintenance Hell ?

It can be … but it does not have to !

Page 11: Unit tests = maintenance hell ?

ROI

Codebase size

Valu

e vs

Cos

t of

Uni

t tes

ts

WTF?

Page 12: Unit tests = maintenance hell ?

Solution 1 : give up on Unit Tests

“Legacy Code is code without Tests”Michael Feathers

Working Effectively with Legacy Code

Codebase size

Mai

ntai

nabi

lity

of c

odeb

ase

Page 13: Unit tests = maintenance hell ?

Solution 2 : reduce the cost of test maintenance !

Codebase size

Valu

e vs

Cos

t of

Uni

t tes

ts

WIN !

Page 14: Unit tests = maintenance hell ?

REDUCING TEST MAINTENANCE COSTS

Page 15: Unit tests = maintenance hell ?

TIP #1 : GET PROPER TOOLS

Page 16: Unit tests = maintenance hell ?

Tools to manage thousands of tests

– Exploring tests / results– Run All– Run/Debug Current Test– Run All Tests in current

Test Class – Re-run last executed

tests– …

• VS2012 Test Explorer– Just kidding !

• Telerik JustCode• JetBrains ReSharper

Page 17: Unit tests = maintenance hell ?

Continuous Testing

• NCrunch !– Runs tests continuously– Reports results without rebuilding or saving the files !– Impacted tests are run first– Tests run in parallel

• Expensive but worth it ! (159$/289$)

– Give it a try http://www.ncrunch.net/– Free alternative : http://continuoustests.com/

Page 18: Unit tests = maintenance hell ?

TIP #2 : GET ORGANIZED

Page 19: Unit tests = maintenance hell ?

Define conventionsConvention Choice

Test Projects [ProjectNamespace].TestsTest Classes One/class to test: [TestedClass]TestTest Methods [MethodName]_with_[Condition]_[ExpectedOutcom

e]Structure Arrange/Act/Assert or Given/When/ThenHelper methods In Test Class (private static)

In Test Project in namespace TestUtilsIn dedicated project « Test Support »

Which convention you choose does not matter, as long as it’s used by everybody !

Page 20: Unit tests = maintenance hell ?

Use « standard » variable names / prefixes

• Common concepts :– sut (System Under Test)– actual (result of the action)– expected (expected value for the result)

• Benefits : – Makes tests more homogenous – No need to think of it when writing the test– Resistant to class renaming !

Page 21: Unit tests = maintenance hell ?

Typical structure

[TestMethod]public void SomeMethod_with_SomeConditions_must_DoSomething(){ // Arrange var sut = MakeSut(); var expected = "what it should return"; // Act var actual = sut.DoSomething();

// Assert Assert.AreEqual(expected, actual, "Should have done something");}

Page 22: Unit tests = maintenance hell ?

TIP #3 : MAKE WRITING TESTS CHEAP AND EASY !

Page 23: Unit tests = maintenance hell ?

Use templates / snippets

• Commonly created items :– Test Class– Test Methods – Test Helper Methods

• … and share them with the team !

• Examples : – aaa, aae, any …

Page 24: Unit tests = maintenance hell ?

TIP #4 : MAKE YOUR TESTS REFACTORING-FRIENDLY

Page 25: Unit tests = maintenance hell ?

It will change !

• In 3 minutes / days / weeks … • Be ready !

“The only constant is change”Heraclitus of Ephesus

5th century BC

Page 26: Unit tests = maintenance hell ?

Constructors

• Dependency Injection entry point– Changes when dependencies are added/removed– Impact in every test !

• Encapsulate it in a helper Method

Page 27: Unit tests = maintenance hell ?

MakeSut()

– Default value for dependencies– Adding dependencies does not impact tests

private static ClassToTest MakeSut( IDependency1 dep1 = null, IDependency2 dep2 = null){

dep1 = dep1 ?? new Mock<IDependency1>().Object; dep2 = dep2 ?? new Mock<IDependency2>().Object;

return new ClassToTest(dep1, dep2);}

Page 28: Unit tests = maintenance hell ?

Test Data creation

• Classes will change– New properties– Updated constructors ….

• Automate generation of « auxiliary » test objects

Page 29: Unit tests = maintenance hell ?

AutoFixture

• Creates instances of classes– Populates constructor

arguments– Populates properties– Recursive– Values derived from

Property names

https://github.com/AutoFixture/AutoFixture/wiki/Cheat-Sheet

var fixture = new Fixture();var user = fixture.Create<User>();

> Install-Package AutoFixture

Page 30: Unit tests = maintenance hell ?

Test-specific comparison

• Comparing objects is common– Actual vs expected– Should not override Equals() for the tests

• Adding properties can break comparison

Page 31: Unit tests = maintenance hell ?

Semantic Comparison var actualUser = new User(12, "[email protected]"); var expectedUser = new User(13, "[email protected]");

actualUser.AsSource().OfLikeness<User>().ShouldEqual(expectedUser); Ploeh.SemanticComparison.LikenessException: The provided value

ProductionCode.Lib.Data.User did not match the expected value ProductionCode.Lib.Data.User. The following members did not match:- Id.- EmailAddress.

actualUser.AsSource().OfLikeness<User>() .Without(u=> u.Id) .ShouldEqual(expectedUser);

> Install-Package SemanticComparison

Page 32: Unit tests = maintenance hell ?

TO CONCLUDE

Page 33: Unit tests = maintenance hell ?

Working with many Unit Tests

• … is hard• Requires extra care

– Up-front– During code

maintenance

• But pain can be reduced by:– Appropriate tools– Good habits

TIPS#1 Proper Tools

– Good Test Runner– Continuous Tests

#2 Get organized– Conventions– Naming

#3 Make Writing Tests Cheap and easy

– Templates/snippets

#4 Prepare for changes– Encapsulate constructors– Automate object Creation– Automate object comparison

Page 34: Unit tests = maintenance hell ?

Recommended read• xUnit Test Patterns: Refactoring Test

Code by Gerard Meszaros – http://xunitpatterns.com/

• Zero-Friction TDD by Mark Seemann– http://blog.ploeh.dk/2009/01/28/Zero-

FrictionTDD/

Page 35: Unit tests = maintenance hell ?

THANKS !QUESTIONS ?

Thibaud DESODT@tsimbalar