@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 cycle
It’s all about writing enough code to satisfy specific
conditions and a continuous refactoring of the code
@giorgionatili #mobiletea 14
Analysis tool
Decouple 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 setups
Just 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 fundamentals
If 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
Readable
Never 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 tests
You 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 privacy
Don’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 cases
Use 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
Clarity
The clarity of expectations and assertions is the key
for effective TDD
@giorgionatili #mobiletea 44
Naming
Don’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 descriptions
Tests 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 behaviors
If 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 Responses
Applications rely on external data sources, it’s
important to have clear expectations about external
APIs responses
@giorgionatili #mobiletea 56
Performance
Tests are code: Never ignore performance issues
and bottlenecks
@giorgionatili #mobiletea 57
Mock Data
Mock only the data you are testing. A mock should
be small and understandable
@giorgionatili #mobiletea 58
Contract Tests
Create 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 complexity
If 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 pixels
Don’t use e2e tests for testing layout
implementations, automate (eventually) screenshots
and then examine them
@giorgionatili #mobiletea 69
Counting elements
Don’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
Preconditions
If you cannot define preconditions you cannot write
tests of good quality, potentially there is a big
misunderstanding about requirements
@giorgionatili #mobiletea 79
Quality
The quality of a test can be highly opinionated; let’s
find a metric that is valuable for your organization
@giorgionatili #mobiletea 80
Validate
Write tests to validate the understanding of the
behaviors a software should implement not to
validate the code
@giorgionatili #mobiletea 81
Estimate
Writing 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

The Little Shop of TDD Horrors