32
The Cowardly Test-o-phobe’s Guide To iOS Testing

The Cowardly Test-o-Phobe's Guide To Testing

Embed Size (px)

Citation preview

Page 1: The Cowardly Test-o-Phobe's Guide To Testing

The Cowardly Test-o-phobe’s

Guide To iOS Testing

Page 2: The Cowardly Test-o-Phobe's Guide To Testing

Why is testing scary?

• Because you’re not a computer scientist

• Because Java bores you rigid

• Because there’s nothing in life more tedious thana “thought leader”

• Because you get paid to ship apps

Page 3: The Cowardly Test-o-Phobe's Guide To Testing

Why is testing important?

• You’ll write code with fewer bugs in it

• You’ll introduce fewer bugs as the project develops

• You’ll document the project without writing any docs

• You’ll knit yourself a security blanket

Page 4: The Cowardly Test-o-Phobe's Guide To Testing

In the next 40 mins…

• I’ll try to convince you that it’s not all *that* scary

• I’ll show you how to get started, even on an existing project

• I’ll show you some tools you can start using on Monday

Page 5: The Cowardly Test-o-Phobe's Guide To Testing

The basics

• Does my code do what it’s supposed to do?

• Does my code cope with unexpected values?

• Does my code break when I change things?

Page 6: The Cowardly Test-o-Phobe's Guide To Testing

Test first

• Write a test to describe what you want your code to do.

• Run the test and watch it fail.

• Write the code you need to get the test to pass.

• Rinse and repeat.

Page 7: The Cowardly Test-o-Phobe's Guide To Testing

Why not test last?

• Because there’s no motivation to test once it runs

• Because there’s never time

• Because you’re confirming your own prejudices

Page 8: The Cowardly Test-o-Phobe's Guide To Testing

Test first

• Write a failing test - RED

• Write the code to make it pass - GREEN

• Write the next test

• Write the code to make it - and all the previous tests - pass REFACTOR

Page 9: The Cowardly Test-o-Phobe's Guide To Testing

Challenges of testing iOS

• Unit testing is designed around testing code

• iOS apps are largely interface driven

• How do you test the effect of taps, touches, swipes and pinches?

Page 10: The Cowardly Test-o-Phobe's Guide To Testing

The tools

• You’ll need a test framework

• Two basic styles:

• JUnit

• RSpec

• Xcode ships with XCTest, which is a JUnit-style

Page 11: The Cowardly Test-o-Phobe's Guide To Testing

Which one?

• Kiwi - a personal choice, but I dislike the JUnit syntax

• Kiwi also includes a nice mocking framework, of which more later

• Other alternatives are available

• Bottom line: use what you feel most comfortable with

Page 12: The Cowardly Test-o-Phobe's Guide To Testing

UI testing approaches• “Robot fingers”

• Borrowed from the web world

• Peers inside the view hierarchy and checks what’s going on

• It works, but it’s fiddly to set up, fiddly to use, and SLOW

Page 13: The Cowardly Test-o-Phobe's Guide To Testing

UI testing approaches• Testing with code

• UI interactions are passed down into code via IBAction methods

• The IBAction methods are our code, so let’s test that to make sure everything works.

• Works on the basis there’s no point in testing other people’s code (especially Apple’s!)

Page 14: The Cowardly Test-o-Phobe's Guide To Testing

UI testing approaches

Page 15: The Cowardly Test-o-Phobe's Guide To Testing

The approach

• Instantiate your view controller

• Recreate your view hierarchy

• Manipulate and test your views

• Err…

• That’s it.

Page 16: The Cowardly Test-o-Phobe's Guide To Testing

Dependencies• One of the biggest problems in getting started with

testing an app is how to handle dependencies

• Classes and methods seldom exist in isolation from each other

• What happens if you are reliant on external data sources such as network APIs?

• How do you test your code without nailing up all the supporting objects?

Page 17: The Cowardly Test-o-Phobe's Guide To Testing

Mocking and stubbing

• How to do it

Mocking

Page 18: The Cowardly Test-o-Phobe's Guide To Testing

NOT DANIEL CRAIG

Page 19: The Cowardly Test-o-Phobe's Guide To Testing

Mocking

• Mocking is the process of creating “stunt doubles”

• The mock object stands in for the real thing

• Also known as “duck typing”

• If it looks like a duck, and swims like a duck, and quacks like a duck… it probably is a duck.

Page 20: The Cowardly Test-o-Phobe's Guide To Testing

Stubbing

• Stubbing takes an existing object, and returns a value that you provide

• You can stub mocks that you’ve created

• You can also stub real objects to return canned values

Page 21: The Cowardly Test-o-Phobe's Guide To Testing

Mocking• Creating mock objects:

id myMockedSubclass = [MyClass mock];

• Stubbing methods without return values: ! [myMockedSubclass stub:@selector(stubbedMethod)]; ! [myMockedSubclass stubbedMethod];

• Stubbing methods with return values: ! [myMockedSubclass stub:@selector(myMethod) andReturn:@"the return value”]; ! NSString *returnValue = [myMockedSubclass myMethod];

Page 22: The Cowardly Test-o-Phobe's Guide To Testing

Mocking your objects

id theEnterprise = [Starship mock]; [theEnterprise stub:@selector(warpFactor) andReturn:@9]; ... [communicator report:[theEnterprise warpFactor]];

Page 23: The Cowardly Test-o-Phobe's Guide To Testing

Mocking “real” objects

id mockDefaults = [NSUserDefaults mock]; [[mockDefaults stubAndReturn:@10] valueForKey:@"userId"]; [[[mockDefaults valueForKey:@"userId"] should] equal:@10]; ... NSNumber *userId = [mockDefaults objectForKey:@"userId"];

Page 24: The Cowardly Test-o-Phobe's Guide To Testing

Network testing

Page 25: The Cowardly Test-o-Phobe's Guide To Testing

Testing networks

• What do you do if your tests imply a dependency on a network data source?

• How do you handle variations in responses?

• How do you handle latency?

• How do you deal with throttling and rate limits?

Page 26: The Cowardly Test-o-Phobe's Guide To Testing

Approaches

• Set up a “stunt double” API using something like Node or Sinatra

• Stub network calls and return “canned” values from within your tests

Page 27: The Cowardly Test-o-Phobe's Guide To Testing

OHHTTPStubs

• Returns “canned” values in response to network calls, e.g. from files that you embed in the project

• Can simulate different types of network speed

• Can simulate slow API responses so that you can test how to handle progress indicators or timeouts

Page 28: The Cowardly Test-o-Phobe's Guide To Testing

Capturing the data

• Grab the data using wget and save it into a file

wget “http://site.com/page” -O response.json

• Add the response file to your project bundle

• Serve the response file with OHHTTPStubs

Page 29: The Cowardly Test-o-Phobe's Guide To Testing

Mocking a response[OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) { Examine the URL components: - baseURL - path - relativePath - parameterString etc etc etc Return TRUE when matched } withStubResponse:^OHHTTPStubsResponse*(NSURLRequest *request) { Build and return an OHHTTPStubsResponse object: - load a file from the local filesystem - send back a specific HTTP status code - send back custom headers - send back errors - adjust response and request lead times }];

Page 30: The Cowardly Test-o-Phobe's Guide To Testing

Capturing the data[OHHTTPStubs stubRequestsPassingTest:^BOOL(NSURLRequest *request) { return [request.URL.path isEqualToString:@"/v1/connections"]; } withStubResponse:^OHHTTPStubsResponse *(NSURLRequest *request) { return [[OHHTTPStubsResponse responseWithFileAtPath:OHPathForFileInBundle(@"v1_con.json", nil) statusCode:200 headers:@{@"Content-Type":@"text/json"}] requestTime:4.0f responseTime:1.0f]; !}];

Page 31: The Cowardly Test-o-Phobe's Guide To Testing

and finally…

• Test your user interfaces in code!

• Mock and stub your classes to handle internal dependencies!

• Fake network connections!

• Testing doesn’t have to be scary! , ,

Page 32: The Cowardly Test-o-Phobe's Guide To Testing

I am

[email protected]

adoptioncurve.net

Twitter, GitHub et al @timd

!

We arecentralway.comand are hiring!