The Little Shop of TDD Horrors

Post on 11-Apr-2017

480 views 0 download

Transcript of The Little Shop of TDD Horrors

@giorgionatili #mobiletea 1

The Little Shop of TDD Horrors

a story from Giorgio Natili (the mobile & tdd dude)

@giorgionatili #mobiletea 2

Italian Accent Crash Course

@giorgionatili #mobiletea 3

A few words about me…

@giorgionatili #mobiletea 4

Lead Mobile Engineer (McGraw Hill Education)

@giorgionatili

@giorgionatili #mobiletea 5

Mobile Tea

@giorgionatili #mobiletea 6

www.meetup.com/pro/mobiletea

@giorgionatili #mobiletea 7

Setup and Teardown

Tests clarity and readability

Mocking data

Contract tests

Behaviors driven development

End to end testing

The goals of testing

What we’ll talk about

“We are going to cycle in good and bad practices highlighting potential solutions…”

How we’ll talk about this

@giorgionatili #mobiletea 9

Everything Started with a Red Sign…

@giorgionatili #mobiletea 10

And from a bunch of notes

@giorgionatili #mobiletea 11

What’s TDD

@giorgionatili #mobiletea 12

Test Driven Development

@giorgionatili #mobiletea 13

Development life cycleIt’s all about writing enough code to satisfy specific conditions and a continuous refactoring of the code

@giorgionatili #mobiletea 14

Analysis toolDecouple requirements in independent, negotiable, valuable, estimable, small testable pieces of code

@giorgionatili #mobiletea 15

With TDD you are not lost anymore!

@giorgionatili #mobiletea 16

Set up and tear down

@giorgionatili #mobiletea 17

Easy setup and teardown

Understandable setups keep the test clean and easily comprehensible for everybody

@giorgionatili #mobiletea 18

beforeEach(function() {

provider.init(["course:read:*", "group:read:*", "settings:read:*", "settings:update:*", "activity:read:*", "log:*:*", "node:create:*", "settings:create:*", "system:update:*", "system:read:*", "system:delete:*", "system:create:*", "unit:create:*", "unit:read:*", "node:update:*", "node:read:*", "node:delete:*", "splash:read:*", "path:read:*", "master:update:*", "snapshot:read:*", "lti:grade:*", "master:read:*", "snapshot:update:*", "history:read:*", "lti:appLaunch:*", "lti:contentItemReturn:*", "appAction:annotationBundle.js:*", "appAction:apps:*", "appAction:annotation.js:*", "openId:read:*", "app:read:*", "activityOutcome:activitySubmission:*", "search:read:*", "userOrgProfile:read:*", "lti:contentItemSelectionReturn:*", "history:create:*", "eula:read:*", "lti:editActivity:*", "userAppCategoryPref:update:*", "platformArtifacts:read:*", "userAppCategoryPref:read:*", "userAppCategoryPref:delete:*", "userAppCategoryPref:create:*", "appCategory:read:*", "appActivity:update:3,4,16,48,49", "appActivity:findAddible:16,48,49", "nextbook:read:*", "appActivity:read:*", "lti:addActivity:*", "activityOutcome:create:*", "activityOutcome:read:*", "activityOutcome:update:*" ]);

});

Overcomplicated setup is a symptom of poor (test(s)) organization!

@giorgionatili #mobiletea 19

Eventually decouple setupsJust in case you really need complicated setups decouple them from tests and include them in the setup…

@giorgionatili #mobiletea 20

Essentials Tests

@giorgionatili #mobiletea 21

Test the fundamentalsIf you are not 100% test covered you are not a bad person!

@giorgionatili #mobiletea 22

describe( 'AppCtrl', function() { describe( 'isCurrentUrl', function() { var AppCtrl, $location, $scope;

beforeEach( module( 'ngBoilerplate' ) );

beforeEach( inject( function( $controller, _$location_, $rootScope ) { $location = _$location_; $scope = $rootScope.$new(); AppCtrl = $controller( 'AppCtrl', { $location: $location, $scope: $scope }); }));

it( 'should pass a dummy test', inject( function() { expect( AppCtrl ).toBeTruthy(); })); }); });

Don’t take advantage from this!

@giorgionatili #mobiletea 23

Test, design and code quality

@giorgionatili #mobiletea 24

Big up front design is not TDD

It’s not based on cycles and it’s not how you would design a component…

@giorgionatili #mobiletea 25

Big projects should still follow best practices…

@giorgionatili #mobiletea 26

Tests are code, treat them well

Write small, readable and decoupled tests. Tests are part of your code base, don’t write garbage code!

@giorgionatili #mobiletea 27

Treat your tests as a welcome guests

@giorgionatili #mobiletea 28

Refactor on green Don’t refactor code or tests until the tests are not green…

@giorgionatili #mobiletea 29

Readability

@giorgionatili #mobiletea 30

ReadableNever write tests that nobody wants or is able to read, you’ll stop to read them too

@giorgionatili #mobiletea 31

@implementation CardTests

- (void)testFlag { [self login]; NSManagedObjectContext *context = [CoreDataManager sharedManager].operationContext; Section *testSection = [Section sectionForUpsertWithSectionId:@(1) forUserId:self.testUserId inContext:context];

// Completed activities should not show a due soon indicator even when due soon. Activity *activityNotStarted = [Activity activityForUpsertWithActivityId:@(2) forSection:testSection inContext:context]; activityNotStarted.progressStatus = ActivityProgressStatusNotYetStarted; activityNotStarted.due = [NSDate distantFuture]; Card *cardForActivityNotStarted = [Card cardForUpsertWithActivityDue:activityNotStarted]; XCTAssertEqualObjects(SCLocStr(@"ACTIVITY_FLAG_NOT_STARTED"), cardForActivityNotStarted.flag);

// Repeated for 6 different scenarios…

@end

Boring and not useful

@giorgionatili #mobiletea 32

Do you like to read like this?

@giorgionatili #mobiletea 33

Time box writing testsYou should be driven away from writing long tests and large amounts of code to satisfy them

@giorgionatili #mobiletea 34

Privacy

@giorgionatili #mobiletea 35

Respect the privacyDon’t expose methods just because you have to test it: well-designed public methods should use them in such a way they don’t need be directly tested

@giorgionatili #mobiletea 36

Reflection + methods swizzling

Don’t expose private methods - even temporarily - you are terrorizing your own design

@giorgionatili #mobiletea 37

Repetitive Cases

@giorgionatili #mobiletea 38

Automate repetitive casesUse generative tests framework to mock repetitive cases in your tests

@giorgionatili #mobiletea 39

describe('pow', function() { it('works for simple cases', function() { assert.equal(pow(2, 1), 2); assert.equal(pow(2, 2), 4); assert.equal(pow(2, 5), 32); assert.equal(pow(2, 8), 256); assert.equal(pow(3, 2), 9); assert.equal(pow(10, 4), 10000); assert.equal(pow(1, 99), 1); }); });

From this mess…

@giorgionatili #mobiletea 40

forAll([gentest.types.int, gentest.types.int],

'pow works like builtin',

function(base, exponent) { var builtinPow = Math.pow(base, exponent); var ourPow = pow(base, exponent);

return (builtinPow === ourPow || relativeErrorWithin(0.000000001, builtinPow, ourPow)); });

To a better code!

@giorgionatili #mobiletea 41

You feel better!

@giorgionatili #mobiletea 42

Clarity

@giorgionatili #mobiletea 43

ClarityThe clarity of expectations and assertions is the key for effective TDD

@giorgionatili #mobiletea 44

NamingDon’t be worried about the length of the names, a right name is the key to be understood by the others

@giorgionatili #mobiletea 45

Poor descriptionsTests descriptions are one of the best sources of documentation, never ignore the importance of providing a good description

@giorgionatili #mobiletea 46

Respect laziness Never force a stakeholder to read the code contained in a test to understand its purpose

@giorgionatili #mobiletea 47

Arrange, Act, Assert (AAA)Separate what is going to be tested from the setups and keep the verification steps clearly identified

@giorgionatili #mobiletea 48

Conditional Behaviors

@giorgionatili #mobiletea 49

Avoid conditional behaviorsIf you start to add conditionals to determine if your code is executed by the tests suites, it means that you are in danger

@giorgionatili #mobiletea 50

Ambiguous behaviors are dangerous!

@giorgionatili #mobiletea 51

“TDD is not about preventing bugs, it’s about proving the exactness of behaviors”

@giorgionatili #mobiletea 52

There are unpredictable conditions!

@giorgionatili #mobiletea 53

but you can still mitigate them…

@giorgionatili #mobiletea 54

Network Responses and API

@giorgionatili #mobiletea 55

Network ResponsesApplications rely on external data sources, it’s important to have clear expectations about external APIs responses

@giorgionatili #mobiletea 56

PerformanceTests are code: Never ignore performance issues and bottlenecks

@giorgionatili #mobiletea 57

Mock DataMock only the data you are testing. A mock should be small and understandable

@giorgionatili #mobiletea 58

Contract TestsCreate tests in a separate environment that checks the sanity of the external API you rely on

@giorgionatili #mobiletea 59

'use strict'; var supertest = require('supertest-as-promised'); var request = supertest('https://ngcourse.herokuapp.com'); var assert = require('chai').assert;

describe('Backend API', function() { it ('should return the list of users', function() { return request.get('/api/v1/users') .expect(200); }); });

Contract Tests in Practice

@giorgionatili #mobiletea 60

Behaviors

@giorgionatili #mobiletea 61

Behaviors Focus on testing software behaviors rather then single units of code

@giorgionatili #mobiletea 62

Organize behaviors Group tests and behaviors that are tied to specific, testable functionality of your software

@giorgionatili #mobiletea 63

Connect behaviors Create a connection between behaviors and scenarios with a format like given/then/when

@giorgionatili #mobiletea 64

Divide tests logically

Never violate the Single Responsibility Principle neither when writing tests, keep the ordered and in a good shape is the key to get the more value from them…

@giorgionatili #mobiletea 65

Measure complexityIf you are not able to organize your tests in such a way it means that you are dealing with confusing (and poor!) requirements

@giorgionatili #mobiletea 66

Scenarios -> Use Cases -> Behaviors

This connection is the key to defining tests that clearly describe a feature and its acceptance criteria

@giorgionatili #mobiletea 67

End 2 End Testing

@giorgionatili #mobiletea 68

Test for pixelsDon’t use e2e tests for testing layout implementations, automate (eventually) screenshots and then examine them

@giorgionatili #mobiletea 69

Counting elementsDon’t use e2e testing to count UI elements, use them to describe how the UI *should change* with a specific behavior

@giorgionatili #mobiletea 70

Writing E2E tests

Never wait too much, start to write end user tests as soon as the requirements are ready, the lack of automation can bring to not reliable outputs

@giorgionatili #mobiletea 71

The Goals of Testing

@giorgionatili #mobiletea 72

Do you ever asked to yourself?

@giorgionatili #mobiletea 73

Profitable Tests should always support the end goal of making profit from a software

@giorgionatili #mobiletea 74

Maintainability Tests are a means to increase maintainability of a software

@giorgionatili #mobiletea 75

Common understanding Don’t separate developers and testers! Keeping them together allows you to have testers that understand the app internals

@giorgionatili #mobiletea 76

Interchangeability Having pairing working alternatively on code and tests is the key to having different perspectives and to improve interchangeability in your team

@giorgionatili #mobiletea 77

Conclusions

@giorgionatili #mobiletea 78

PreconditionsIf you cannot define preconditions you cannot write tests of good quality, potentially there is a big misunderstanding about requirements

@giorgionatili #mobiletea 79

QualityThe quality of a test can be highly opinionated; let’s find a metric that is valuable for your organization

@giorgionatili #mobiletea 80

ValidateWrite tests to validate the understanding of the behaviors a software should implement not to validate the code

@giorgionatili #mobiletea 81

EstimateWriting tests take time. Count it in your estimates but keep always in mind the time that is then saved during the maintaining phase

@giorgionatili #mobiletea 82

Questions

@giorgionatili #mobiletea 83

Special thanks to:

•Shawn Pucknell•Jacqueline Poole•Rafael Fernandes• Jonathan Barton

@giorgionatili #mobiletea 84

THANK YOU