Transcript
Page 1: Real World Mocking In Swift

���� �����

Good morning!

Page 2: Real World Mocking In Swift

Real World Mocking In Swift

Page 3: Real World Mocking In Swift

You Want To Write Tests

Page 4: Real World Mocking In Swift

But You Don’t Want Them

To Mess Up Your

Real Stuff

Page 5: Real World Mocking In Swift

Or Be Slow

Page 6: Real World Mocking In Swift

let session = NSURLSession()let url = NSURL(string: "http://www.tryswiftconf.com")!let task = session.dataTaskWithURL(url) { (data, _, _) -> Void in if let data = data { let string = String(data: data, encoding: NSUTF8StringEncoding) print(string) }}task.resume()

Page 7: Real World Mocking In Swift

OCMock can't save you now

Page 8: Real World Mocking In Swift

class HTTPClientTests: XCTestCase { var subject: HTTPClient! let session = MockURLSession()

override func setUp() { super.setUp() subject = HTTPClient(session: session) }

Page 9: Real World Mocking In Swift

class HTTPClientTests: XCTestCase { var subject: HTTPClient! let session = MockURLSession()

override func setUp() { super.setUp() subject = HTTPClient(session: session) }

func test_GET_RequestsTheURL() { let url = NSURL(string: "http://www.tryswiftconf.com")!

subject.get(url) { (_, _) -> Void in }

Page 10: Real World Mocking In Swift

class HTTPClientTests: XCTestCase { var subject: HTTPClient! let session = MockURLSession()

override func setUp() { super.setUp() subject = HTTPClient(session: session) }

func test_GET_RequestsTheURL() { let url = NSURL(string: "http://www.tryswiftconf.com")!

subject.get(url) { (_, _) -> Void in }

XCTAssert(session.lastURL === url) }}

Page 11: Real World Mocking In Swift
Page 12: Real World Mocking In Swift

It Will Take A Lot Of

Time

Page 13: Real World Mocking In Swift

You Will Wonder If It’s

Worth It

Page 14: Real World Mocking In Swift
Page 15: Real World Mocking In Swift

Why Use Mocks» Make tests faster (like 1000s of times faster!) !

» Increase coverage of test suite "

» Make tests more robust #

Page 16: Real World Mocking In Swift

Testing

Page 17: Real World Mocking In Swift
Page 18: Real World Mocking In Swift

The TimeTo Write Tests Is

Page 19: Real World Mocking In Swift

Now

Page 20: Real World Mocking In Swift
Page 21: Real World Mocking In Swift
Page 22: Real World Mocking In Swift

DependencyInjection

Page 23: Real World Mocking In Swift

class VideoCaptureManager: NSObject { var userDefaults: UserDefaultsProtocol

//MARK: - Initializers override init() { self.userDefaults = UserDefaults() }

convenience init(userDefaults: UserDefaultsProtocol) { self.init() self.userDefaults = userDefaults }}

Page 24: Real World Mocking In Swift

“Dependency injection means giving an object its instance variables. Really. That's it.”James Shore

Page 25: Real World Mocking In Swift

Why Not Just Use A

Singleton?

Page 26: Real World Mocking In Swift

class VideoUploadManager { static let sharedInstance = VideoUploadManager()}

class TimeMachineAPI { func uploadVideo(videoRecording: VideoRecording) { VideoUploadManager.sharedInstance.upload(videoRecording: self.videoRecording, completion: { (error) -> Void in if let error = error { Log.error(error.localizedDescription) } }) }}

Page 27: Real World Mocking In Swift

Why Use Dependency Injection» Easy customization !

» Clear ownership "

» Testability #

Page 28: Real World Mocking In Swift

Constructor injection

Page 29: Real World Mocking In Swift

Test Doubles

Page 30: Real World Mocking In Swift

Types of Test Doubles» Stubs !

» Mocks "

» Partial mocks #

Page 31: Real World Mocking In Swift

Stubs

Page 32: Real World Mocking In Swift

“Fakes a response to method calls of an object”Unit Testing Tutorial: Mocking Objects

Page 33: Real World Mocking In Swift

class StubTimeMachineAPI: TimeMachineAPI { var videoUrl = "https://www.youtube.com/watch?v=SQ8aRKG9660"

func getVideoFor(year: Int) -> String { return videoUrl }}

Page 34: Real World Mocking In Swift

Mocks

Page 35: Real World Mocking In Swift

“Let you check if a method call is performed or if a property is set”Unit Testing Tutorial: Mocking Objects

Page 36: Real World Mocking In Swift

class MockTimeMachine: TimeMachine { var timeTravelWasCalled = false

mutating func timeTravelTo(year: Int) { timeTravelWasCalled = true }}

Page 37: Real World Mocking In Swift

PartialMock

Page 38: Real World Mocking In Swift

“Any actual object which has been wrapped or changed ”Justin Searls

Page 39: Real World Mocking In Swift

“to provide artificial responses to some methods but not others”Justin Searls

Page 40: Real World Mocking In Swift

Partial Mocks Are An

Anti-pattern

Page 41: Real World Mocking In Swift

What’s Wrong With Partial Mocks?» Challenging to set up !

» Decreases the comprehensibility of the test "

Page 42: Real World Mocking In Swift

What’s Real?What’s Fake?

Page 43: Real World Mocking In Swift

Mocking

Page 44: Real World Mocking In Swift
Page 45: Real World Mocking In Swift

Mocking In SwiftVia Protocols

Page 46: Real World Mocking In Swift

“This kind of testing is really similar to what you get with mocks, but it’s so much better.”Protocol-Oriented Programming in Swift

Page 47: Real World Mocking In Swift

“Mocks are inherently fragile. ”Protocol-Oriented Programming in Swift

Page 48: Real World Mocking In Swift

“You have to couple your testing code”Protocol-Oriented Programming in Swift

Page 49: Real World Mocking In Swift

“to the implementation details of the code under test.”Protocol-Oriented Programming in Swift

Page 50: Real World Mocking In Swift

Plays WellWith StructsAnd Classes

Page 51: Real World Mocking In Swift

Protocols HelpWhen There’sInternal Dependencies

Page 52: Real World Mocking In Swift
Page 53: Real World Mocking In Swift

They SaidDon’t Mock TypesYou Don’t Own

Page 54: Real World Mocking In Swift
Page 55: Real World Mocking In Swift

Why It’s Bad To Mock Types You Don’t Own

» Have to be sure that the behavior you implement in a mock matches the external library

» The external library could change, breaking your mock

Page 56: Real World Mocking In Swift

Mocking Apple Framework Classesclass UserDefaultsMock: UserDefaultsProtocol {

private var objectData = [String : AnyObject]()

func objectForKey(key: UserDefaultsKey) -> AnyObject? { return objectData[key.name] }

func setObject(value: AnyObject?, forKey key: UserDefaultsKey) { objectData[key.name] = value }

func removeObjectForKey(key: UserDefaultsKey) { objectData[key.name] = nil }

}

Page 57: Real World Mocking In Swift

Time Traveler

Times

Page 58: Real World Mocking In Swift

Test That Uses UserDefaultsMockfunc testNotificationSettingsLoad() { let userDefaultsMock = UserDefaultsMock() mockUserDefaults.setObject("NEVER", forKey: "timeMachineBreakingNewsPushNotification") mockUserDefaults.setObject("NEVER", forKey: "timeMachineDailyDigestPushNotification")

let dataProvider = PushNotificationsDataProvider(userDefaults: mockUserDefaults) let expectedFrequencies: [PushNotificationFrequency] = [.Never, .All, .All, .Never]

XCTAssertEqual(expectedFrequencies, dataProvider.notificationSettings.values)

}

Page 59: Real World Mocking In Swift

Mocking NSNotificationCenter Was Not Worth It

» Complex !

» Injected throughout entire codebase "

» Limited functionality compared to real object #

» Solves a problem that doesn’t really exist $

Page 60: Real World Mocking In Swift

They SaidDon’t MockValue Types

Page 61: Real World Mocking In Swift

“When you’re doing...simple data in and data out, you don’t need mocking or stubbing. ”Andy Matuschak

Page 62: Real World Mocking In Swift

“You can pass a value into a function, then look at the resulting value.”Andy Matuschak

Page 63: Real World Mocking In Swift
Page 64: Real World Mocking In Swift

“Try making your reference types immutable”Joe Groff

Page 65: Real World Mocking In Swift
Page 66: Real World Mocking In Swift

What Makes a Good Mock» Quick and easy to write

» Relatively short and does not contain tons of information you don’t need

» Legitimate reason to not use real object

Page 67: Real World Mocking In Swift

I am thoughtfulabout what gets mocked

and why

Page 68: Real World Mocking In Swift

Fellow time travelers

Page 69: Real World Mocking In Swift

Let’s look towards the future

Page 70: Real World Mocking In Swift

SwiftMocking Frameworks

Page 71: Real World Mocking In Swift

DobbyMockFiveSwiftMock

Page 72: Real World Mocking In Swift

Cuckoo

Page 73: Real World Mocking In Swift

A WorldWithout Mocks

Page 74: Real World Mocking In Swift

Wrap Up! If you want to improve your codebase, write tests! Mocks allow you to write great tests! Create simple mocks that will last

Page 75: Real World Mocking In Swift

Write MocksAnd Use ThemFor Great Good

Page 76: Real World Mocking In Swift

! " !


Top Related