more maintainable - Unlike most material on TDD, which only covers basic examples. - Principles that you can apply to any scenario in test-driven development.
- How to make it more maintainable - Unlike most material on TDD, which only covers basic examples. - Principles that you can apply to any scenario in test-driven development.
Underlaying principles of TDD - How to make it more maintainable - Unlike most material on TDD, which only covers basic examples. - Principles that you can apply to any scenario in test-driven development.
Underlaying principles of TDD Better user experience - How to make it more maintainable - Unlike most material on TDD, which only covers basic examples. - Principles that you can apply to any scenario in test-driven development.
allDogs:^(NSArray *dogs) { capturedDogs = dogs; } failure:^(NSError *error) { }]; [[expectFutureValue(capturedDogs) shouldEventually] equal:@[@{@"name":@"perro",@"color":@"brown"}, @{@"name":@"tomas",@"color":@"black"} ]]; }); BAM! We have our first test Raise you hand if you see any problems with this test What is wrong with it? It’s hitting the real network: undeterministic, slow dependency Real life test case Principle TDD: isolate code from undeterministic and slow depencencies.
allDogs:^(NSArray *dogs) { capturedDogs = dogs; } failure:^(NSError *error) { }]; [[expectFutureValue(capturedDogs) shouldEventually] equal:@[@{@"name":@"perro",@"color":@"brown"}]]; }); BAM! No network! No it’s deterministic, and fast. Raise you hand if you see any problems with this test. What is wrong with it?
allDogs:^(NSArray *dogs) { capturedDogs = dogs; } failure:^(NSError *error) { }]; [[expectFutureValue(capturedDogs) shouldEventually] equal:@[@{@"name":@"perro",@"color":@"brown"}]]; }); AFJSONRequestOperation *mockOp = [AFJSONRequestOperation mock]; BAM! No network! No it’s deterministic, and fast. Raise you hand if you see any problems with this test. What is wrong with it?
allDogs:^(NSArray *dogs) { capturedDogs = dogs; } failure:^(NSError *error) { }]; [[expectFutureValue(capturedDogs) shouldEventually] equal:@[@{@"name":@"perro",@"color":@"brown"}]]; }); AFJSONRequestOperation *mockOp = [AFJSONRequestOperation mock]; [AFJSONRequestOperation stub:@selector(JSONRequestOperationWithRequest:success:failure:) withBlock:^id(NSArray *params) { return mockOp; }]; BAM! No network! No it’s deterministic, and fast. Raise you hand if you see any problems with this test. What is wrong with it?
allDogs:^(NSArray *dogs) { capturedDogs = dogs; } failure:^(NSError *error) { }]; [[expectFutureValue(capturedDogs) shouldEventually] equal:@[@{@"name":@"perro",@"color":@"brown"}]]; }); AFJSONRequestOperation *mockOp = [AFJSONRequestOperation mock]; [AFJSONRequestOperation stub:@selector(JSONRequestOperationWithRequest:success:failure:) withBlock:^id(NSArray *params) { return mockOp; }]; __block NSURLRequest *capturedRequest; __block void (^capturedSuccess)(NSURLRequest *request, NSHTTPURLResponse *response, id JSON); BAM! No network! No it’s deterministic, and fast. Raise you hand if you see any problems with this test. What is wrong with it?
allDogs:^(NSArray *dogs) { capturedDogs = dogs; } failure:^(NSError *error) { }]; [[expectFutureValue(capturedDogs) shouldEventually] equal:@[@{@"name":@"perro",@"color":@"brown"}]]; }); AFJSONRequestOperation *mockOp = [AFJSONRequestOperation mock]; [AFJSONRequestOperation stub:@selector(JSONRequestOperationWithRequest:success:failure:) withBlock:^id(NSArray *params) { return mockOp; }]; __block NSURLRequest *capturedRequest; __block void (^capturedSuccess)(NSURLRequest *request, NSHTTPURLResponse *response, id JSON); capturedRequest = params[0]; capturedSuccess = params[1]; BAM! No network! No it’s deterministic, and fast. Raise you hand if you see any problems with this test. What is wrong with it?
(e.g. validation, ask for more permissions) 3. Known non-recoverable errors. (e.g. server is down, rate limiting) 4. “How the fu*k did I get here?” errors
(BOOL)shouldRecoverByReauthorizing; - (BOOL)shouldRecoverByRequestingMorePermissions; Let’s say that we are implementing the Facebook SDK used privately forms an error from a response
(BOOL)shouldRecoverByReauthorizing; - (BOOL)shouldRecoverByRequestingMorePermissions; - (BOOL)shouldRecoverByNotifyingUser; Let’s say that we are implementing the Facebook SDK used privately forms an error from a response
NSError *facebookError = [NSError facebookAPIErrorWithResponse:JSON]; if ([facebookError shouldRecoverByReauthorizing]) { // Reauthorize } else if ([facebookError shouldRecoverByRequestingMorePermissions]) { // Request more permissions } else if ([facebookError shouldRecoverByNotifyingUser]) { } 3. Known non-recoverable errors. (e.g. server is down, rate limiting) 4. “How the fu*k did I get here?” errors log remotely - alternative to crash reports TIME? More slides?
NSError *facebookError = [NSError facebookAPIErrorWithResponse:JSON]; if ([facebookError shouldRecoverByReauthorizing]) { // Reauthorize } else if ([facebookError shouldRecoverByRequestingMorePermissions]) { // Request more permissions } else if ([facebookError shouldRecoverByNotifyingUser]) { } failure([NSError facebookSDKErrorWithError:error]); 3. Known non-recoverable errors. (e.g. server is down, rate limiting) 4. “How the fu*k did I get here?” errors log remotely - alternative to crash reports TIME? More slides?
NSError *facebookError = [NSError facebookAPIErrorWithResponse:JSON]; if ([facebookError shouldRecoverByReauthorizing]) { // Reauthorize } else if ([facebookError shouldRecoverByRequestingMorePermissions]) { // Request more permissions } else if ([facebookError shouldRecoverByNotifyingUser]) { } else { failure([NSError genericError]); } failure([NSError facebookSDKErrorWithError:error]); 3. Known non-recoverable errors. (e.g. server is down, rate limiting) 4. “How the fu*k did I get here?” errors log remotely - alternative to crash reports TIME? More slides?
NSError *facebookError = [NSError facebookAPIErrorWithResponse:JSON]; if ([facebookError shouldRecoverByReauthorizing]) { // Reauthorize } else if ([facebookError shouldRecoverByRequestingMorePermissions]) { // Request more permissions } else if ([facebookError shouldRecoverByNotifyingUser]) { } else { failure([NSError genericError]); } failure([NSError facebookSDKErrorWithError:error]); // Ensure consistent state 3. Known non-recoverable errors. (e.g. server is down, rate limiting) 4. “How the fu*k did I get here?” errors log remotely - alternative to crash reports TIME? More slides?
NSError *facebookError = [NSError facebookAPIErrorWithResponse:JSON]; if ([facebookError shouldRecoverByReauthorizing]) { // Reauthorize } else if ([facebookError shouldRecoverByRequestingMorePermissions]) { // Request more permissions } else if ([facebookError shouldRecoverByNotifyingUser]) { } else { failure([NSError genericError]); } failure([NSError facebookSDKErrorWithError:error]); // Ensure consistent state // Log facebookError in a remote service 3. Known non-recoverable errors. (e.g. server is down, rate limiting) 4. “How the fu*k did I get here?” errors log remotely - alternative to crash reports TIME? More slides?
Take forward compatibility into account Isolate test from undeterministic and slow dependencies. Don’t modify implementation and tests at the same time. Recap
Take forward compatibility into account Isolate test from undeterministic and slow dependencies. Don’t modify implementation and tests at the same time. Don’t couple test with implementation details Recap
Take forward compatibility into account Isolate test from undeterministic and slow dependencies. Don’t modify implementation and tests at the same time. Don’t couple test with implementation details Group errors by recover strategy Recap
Take forward compatibility into account Isolate test from undeterministic and slow dependencies. Don’t modify implementation and tests at the same time. Don’t couple test with implementation details Group errors by recover strategy Recap