Download - Unit tests = maintenance hell ?

Transcript
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