How not to suck at unit tests

Preview:

Citation preview

@benjamminstl

How Not to Suck at Unit TestsA presentation for Code PaLOUsa April 28, 2015

@benjamminstl

How I’ve Sucked at Unit TestsA presentation for Code PaLOUsa April 28, 2015

@benjamminstl

Ben BishopPurdue University graduate with a degree in Computer Graphics Technology. 10+ years of development experience. Rendr Co-Founder.

@benjamminstl

David Ortinau15+ years of development experience. Xamarin MVP. Beard Enthusiast. Rendr Co-Founder.

@benjamminstl

A little about RendrWe are a people focused software studio, building engaging solutions to solve real world problems and improve lives.

@benjamminstl

@benjamminstl

@benjamminstl

@benjamminstl

@benjamminstl

@benjamminstl

@benjamminstl

GoalsIf you take just one thing from this presentation, then I have achieved my goal.

@benjamminstl

2009

@benjamminstl

Typical Production Experience

Time

Productivity

@benjamminstl

Typical Production Experience

Time

Productivity

We can totally do that! We’re Rockstar Ninjas!

@benjamminstl

Typical Production Experience

Time

Productivity

Noooooo, the world will end! We hate our lives.

@benjamminstl

@benjamminstl

@benjamminstl

A Culture of NO

@benjamminstl

A Culture of Friction

@benjamminstl

NO

NO

NONO

NO

NO

NOT Possible

Can’tNOT within scope

NO

NO Time

@benjamminstl

Friction wastes energyFriction robs us of efficiency

@benjamminstl

@benjamminstl

Scrum

Ken Schwaber

@benjamminstl

@benjamminstl

@benjamminstl

Saying “yes” introduces risk.

@benjamminstl

The Land Scrum Forgothttps://www.youtube.com/watch?v=hG4LH6P8Syk

@benjamminstl

Segue

@benjamminstl

Six Projects with Unit Tests

@benjamminstl

Six “Failures”

@benjamminstl

Failed Attempt #1 at Unit Testing

@benjamminstl

@benjamminstl

Lessons Learned- Couldn’t automate testing through UI- Video streaming is extremely hard to test- Model/View architecture did not facilitate testing- Any testable state was in the view

@benjamminstl

Testable View State

@benjamminstl

Failed Attempt #2 at Unit Testing

@benjamminstl

@benjamminstl

Lessons Learned• Tests that test a server API aren’t Unit Tests• Hard to figure out how to not pollute your database with junk

data• Actually considered “integration test”• Best to separate server tests from app tests• Again, architecture didn’t support true unit tests

@benjamminstl

Separate Server Tests

@benjamminstl

Stay DRY

@benjamminstl

Stay DRY

@benjamminstl

Stay Performant

@benjamminstl

Failed Attempt #3 at Unit Testing

@benjamminstl

@benjamminstl

Lessons Learned• Hard to write tests for already existing classes• Couldn’t test private functions

• Spies• Have your TestCase extend the class you’re testing• Levels!

@benjamminstl

Jason Sonmezhttp://simpleprogrammer.com/2010/12/12/back-to-basics-why-unit-testing-is-hard/

Level 1 Unit Testing is where we have a single class with no external dependencies and no state. We are just testing an algorithm.

Level 2 Unit Testing is where we have a single class with no external dependencies but it does have state. We are setting up an object and testing it as a whole.

Level 3 Unit Testing is when we have a single class with at least one external dependency, but it does not depend on its own internal state.

Level 4 Unit Testing is when we have a single class with at least one external dependency and depends on its own internal state.

@benjamminstl

How do you test protected elements?

@benjamminstl

Test Spy

@benjamminstl

Test Spy

@benjamminstl

Failed Attempt #4 at Unit Testing

@benjamminstl

@benjamminstl

Lessons Learned• Use TestCase data meta tags• ViewModel architecture is very testable• Beware Yak Shaving

• testing setter/getters• constructor assignments!

!

@benjamminstl

Solution

@benjamminstl

Solution

@benjamminstl

Solution

@benjamminstl

Failed Attempt #5 at Unit Testing

@benjamminstl

@benjamminstl

Lessons Learned• Don’t use static/hard-singleton classes

• Static classes and/or extension methods cannot be replaced with Fake or Mock

• TestData brittleness• Use data fixtures like AutoFixture, otherwise you have to

constantly update your test data generators.• When testing integration test behavior not results• Beware of the Red, Green, Refactor blur

@benjamminstl

VMIC

View

CommandInputInvoker OutputInvoker

Mediator

@benjamminstl

@benjamminstl

Testing Results

@benjamminstl

Static Class

@benjamminstl

FakeItEasy

@benjamminstl

FakeItEasy

@benjamminstl

Homegrown Brittleness

@benjamminstl

AutoFixture

@benjamminstl

Failed Attempt #6 at Unit Testing

@benjamminstl

@benjamminstl

Lessons Learned• Set up brittleness

• Don’t use DI containers• Readability

• What is easy to write is not easy to read• Find ways to write less code

• Use interface tools/markup• Binding frameworks• Share code across platforms!

@benjamminstl

Improve Readability

@benjamminstl

Improve Readability

@benjamminstl

SolutionLess code

@benjamminstl

All of the Native, None of the IsolationThe best of both worlds: Code Portability and Tailored UIs

Number of Classes Percent (with Unit Tests) Percent (no Unit Tests)Core 207 43.2% 64.4%Tests 158 32.9%

Android 58* 12.2% 18.1%

iOS 56 11.7% 17.5%

Total 479 (321)

*includes .axml and .xml files

@benjamminstl

All of the Native, None of the IsolationThe best of both worlds: Code Portability and Tailored UIs

Number of Lines Percent (with Unit Tests) Percent (no Unit Tests)Core 9,886 35.3% 44.9%Tests 5,979 21.4%

Android 5,606* 20.0% 20.0%

iOS 6,512 23.3% 29.6%

Total 27,983 (22,004)

*includes .axml and .xml files

@benjamminstl

MVVM

View

ViewModel

(via bindings)

Service

@benjamminstl

Example

@benjamminstl

Closing Thoughts

@benjamminstl

Unit Testing is a habit that is no different than dieting or working out.

@benjamminstl

Small steps to a larger goal works better than trying to be perfect from the get go.

@benjamminstl

Small steps to a larger goal works better than trying to be perfect from the get go.

@benjamminstl

Test Code isn’t easyThe quality of your test code has to be equal to or greater than your production code. If test code is an after thought and isn’t refactored it too will become brittle.

@benjamminstl

Get used to failureA lot of devs want to avoid unit testing because seeing failed tests forces you to deal with the consequences of your change.

@benjamminstl

Ignorance is bliss…Until a client asks you to change something and you don’t know what’s going to break.

@benjamminstl

Research

@benjamminstl

Practice

@benjamminstl

Code Reviews

@benjamminstl

Thank You

David Ortinau 314.280.8445 dave@rendr.io

Ben Bishop 314.775.8800 ben@rendr.io

Recommended