unit testing: special cases
DESCRIPTION
The 4th Dnepropetrovsk iOS Practice Leaders Community Meet-Up, which took place onThursday, September 25. Maxim Koshtenko, an iOS developer with 4+ years of experience in the area, held a presentation in which he told: - about the most widespread problems which appear while writing tests and how to solve them; - how to cover controllers with tests correctly and what should be visible in interface; - why tests do not work for block-based and asynchronous code and how we can fix this; - how to write tests for Core Data models; - many other useful and interesting tips and tricks. The presentation will be interesting for all iOS developers.TRANSCRIPT
![Page 1: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/1.jpg)
Unit TestingSpecial Cases
![Page 2: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/2.jpg)
How to Test
![Page 3: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/3.jpg)
UIViewControllers
How to TestUnit Testing
What Is Testing For?
![Page 4: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/4.jpg)
UIViewControllers Block-based code !
How to TestUnit Testing
What Is Testing For?
![Page 5: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/5.jpg)
UIViewControllers Block-based code CoreData
How to TestUnit Testing
What Is Testing For?
![Page 6: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/6.jpg)
UIViewController
![Page 7: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/7.jpg)
IBOutlets & IBActions viewDidLoad dealloc UINavigationController
UIViewController
![Page 8: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/8.jpg)
IBOutlets & IBActions
Outlet is connected
![Page 9: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/9.jpg)
- (void)setUp { [super setUp]; sut = [ConverterViewController new]; } !- (void)tearDown { sut = nil; [super tearDown]; }
Is Outlet Connected?
![Page 10: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/10.jpg)
- (void)setUp { [super setUp]; sut = [ConverterViewController new]; } !- (void)tearDown { sut = nil; [super tearDown]; } !- (void)testThatTextFieldOutletIsConnected { XCTAssertNotNil(sut.textField, @"outlet should be connected"); }
Is Outlet Connected?
![Page 11: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/11.jpg)
- (void)setUp { [super setUp]; sut = [ConverterViewController new]; } !- (void)tearDown { sut = nil; [super tearDown]; } !- (void)testThatTextFieldOutletIsConnected { XCTAssertNotNil(sut.textField, @"outlet should be connected"); }
Is Outlet Connected?
![Page 12: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/12.jpg)
- (void)setUp { [super setUp]; sut = [ConverterViewController new]; } !- (void)tearDown { sut = nil; [super tearDown]; } !- (void)testThatTextFieldOutletIsConnected { [sut view]; XCTAssertNotNil(sut.textField, @"outlet should be connected"); }
Is Outlet Connected?
![Page 13: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/13.jpg)
IBOutlets & IBActions
Outlet has a right action.
![Page 14: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/14.jpg)
- (void)testButtonActionBinding { [sut view]; NSArray* acts = [sut.button actionsForTarget:sut forControlEvent:UIControlEventTouchUpInside]; XCTAssert([acts containsObject:@"onButton:"], @"should use correct action"); }
Is Action Connected?
![Page 15: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/15.jpg)
IBOutlets & IBActions
The action does the right things.
![Page 16: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/16.jpg)
viewDidLoad
Unit testing of a view controller nearly always means writing the view controller methods differently
![Page 17: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/17.jpg)
viewDidLoad
- should call helper methods
![Page 18: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/18.jpg)
viewDidLoad
- should call helper methods - each of the helper methods should
do just one thing (SOLID principles)
![Page 19: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/19.jpg)
viewDidLoad
- should call helper methods - each of the helper methods should
do just one thing (SOLID principles) - write tests for each of the helper
methods
![Page 20: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/20.jpg)
viewDidLoad
- should call helper methods - each of the helper methods should
do just one thing (SOLID principles) - write tests for each of the helper
methods - test viewDidLoad calls helper
methods (partial mock)
![Page 21: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/21.jpg)
dealloc
setUp tearDown zombie
![Page 22: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/22.jpg)
dealloc
❓hook dealloc method of SUT when setup
![Page 23: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/23.jpg)
dealloc
❓hook dealloc method of SUT when setup ❓record calling of the hook
![Page 24: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/24.jpg)
dealloc
❓hook dealloc method of SUT when setup ❓record calling of the hook ❓verify if hook is called after teardown
![Page 25: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/25.jpg)
Aspects
![Page 26: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/26.jpg)
/// Adds a block of code before/instead/after the current `selector` for a specific instance. - (id<AspectToken>)aspect_hookSelector:(SEL)selector withOptions:(AspectOptions)options usingBlock:(id)block error:(NSError **)error; !/// Called after the original implementation (default) AspectPositionAfter, !/// Will replace the original implementation. AspectPositionInstead, !/// Called before the original implementation. AspectPositionBefore,
Aspects
![Page 27: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/27.jpg)
dealloc
✅ hook dealloc method of SUT when setup ❓ record calling of the hook ❓ verify if hook is called after teardown
Aspects
![Page 28: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/28.jpg)
dealloc
✅ hook dealloc method of SUT when setup ✅ record calling of the hook ❓ verify if hook is called after teardown
Aspects
instance var
![Page 29: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/29.jpg)
dealloc
✅ hook dealloc method of SUT when setup ✅ record calling of the hook ✅ verify if hook is called after teardown
Aspects
instance var
XCTAssert
![Page 30: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/30.jpg)
@interface ConverterViewControllerTests : XCTestCase { ConverterViewController* sut; BOOL _sutDeallocated; } @end !- (void)setUp { [super setUp]; sut = [ConverterViewController new]; _sutDeallocated = NO; [sut aspect_hookSelector:NSSelectorFromString(@"dealloc") withOptions:AspectPositionBefore usingBlock:^(id<AspectInfo> aspectInfo){ _sutDeallocated = YES; } error:nil]; } !- (void)tearDown { sut = nil; XCTAssertTrue(_sutDeallocated, @"SUT is not deallocated"); [super tearDown]; }
dealloc
![Page 31: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/31.jpg)
@interface } @end !- ( [ !!!!!} !- ( [}
dealloc!!!!!!!!!! [sut aspect_hookSelector:NSSelectorFromString(@"dealloc") withOptions:AspectPositionBefore usingBlock:^(id<AspectInfo> aspectInfo){ _sutDeallocated = YES; } error:nil];
![Page 32: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/32.jpg)
UINavigationController
- test push view controller - test pop view controller
![Page 33: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/33.jpg)
UINavigationController
![Page 34: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/34.jpg)
UINavigationController
But
![Page 35: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/35.jpg)
UINavigationController
But
@interface UIViewController (UINavigationControllerItem) ! @property(nonatomic,readonly,retain) UINavigationController* navigationController; ! @end
![Page 36: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/36.jpg)
-(void)testTappingDetailsShouldDisplayDetails { UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:sut]; id mockNav = [OCMockObject partialMockForObject:nav]; [[mockNav expect] pushViewController:[OCMArg any] animated:YES]; [sut onShowDetailsButton:nil]; [mockNav verify]; }
UINavigationController
![Page 37: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/37.jpg)
Choosing not to test view controllers is the decision not to test most of your code.
UIViewController
![Page 38: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/38.jpg)
Testing simple things is simple, and testing complex things is complex
UIViewController
![Page 39: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/39.jpg)
Block-based code
Why does test fail?
![Page 40: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/40.jpg)
Block-based code
! typedef void(^CompletionHandler)(NSArray * result); ! - (void)runAsyncCode:(CompletionHandler)completion { dispatch_async(dispatch_get_main_queue(), ^{ completion(nil); }); }
![Page 41: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/41.jpg)
- (void)testRunAsyncCode { // arrange __block BOOL hasCalledBack = NO; ! // act [sut runAsyncCode:^(NSArray *result) { hasCalledBack = YES; }]; // assert XCTAssert(hasCalledBack, @"Test timed out"); }
Block-based code
![Page 42: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/42.jpg)
- (void)testRunAsyncCode { // arrange __block BOOL hasCalledBack = NO; ! // act [sut runAsyncCode:^(NSArray *result) { hasCalledBack = YES; }]; // assert XCTAssert(hasCalledBack, @"Test timed out"); }
Block-based code
![Page 43: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/43.jpg)
- (void)testRunAsyncCode { // arrange __block BOOL hasCalledBack = NO; ! // act [sut runAsyncCode:^(NSArray *result) { hasCalledBack = YES; }]; // assert XCTAssert(hasCalledBack, @"Test timed out"); }
Block-based code
![Page 44: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/44.jpg)
- (void)testRunAsyncCode { // arrange __block BOOL hasCalledBack = NO; ! // act [sut runAsyncCode:^(NSArray *result) { hasCalledBack = YES; }]; // assert XCTAssert(hasCalledBack, @"Test timed out"); }
Block-based code
![Page 45: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/45.jpg)
- (void)testRunAsyncCode { // arrange __block BOOL hasCalledBack = NO; ! // act [sut runAsyncCode:^(NSArray *result) { hasCalledBack = YES; }]; // assert XCTAssert(hasCalledBack, @"Test timed out"); }
Block-based code
![Page 46: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/46.jpg)
- (void)testRunAsyncCode { // arrange __block BOOL hasCalledBack = NO; ! // act [sut runAsyncCode:^(NSArray *result) { hasCalledBack = YES; }]; // assert XCTAssert(hasCalledBack, @"Test timed out"); }
Block-based code
![Page 47: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/47.jpg)
Block-based code
What can we do?
![Page 48: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/48.jpg)
Block-based code
![Page 49: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/49.jpg)
- (void)testRunAsyncCode { // arrange __block BOOL hasCalledBack = NO; ! // act [sut runAsyncCode:^(NSArray *result) { hasCalledBack = YES; }]; // assert XCTAssert(hasCalledBack, @"Test timed out"); }
Block-based code
![Page 50: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/50.jpg)
- (void)testRunAsyncCode { // arrange __block BOOL hasCalledBack = NO; ! // act [sut runAsyncCode:^(NSArray *result) { hasCalledBack = YES; }]; // assert !!!! ! XCTAssert(hasCalledBack, @"Test timed out"); }
Block-based code
![Page 51: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/51.jpg)
- (void)testRunAsyncCode { // arrange __block BOOL hasCalledBack = NO; ! // act [sut runAsyncCode:^(NSArray *result) { hasCalledBack = YES; }]; // assert NSDate *timeout = [NSDate dateWithTimeIntervalSinceNow:0.1]; while([timeout timeIntervalSinceNow] > 0 && hasCalledBack == NO) { [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:timeout]; } XCTAssert(hasCalledBack, @"Test timed out"); }
Block-based code
![Page 52: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/52.jpg)
- (void)testRunAsyncCode { // arrange __block BOOL hasCalledBack = NO; ! // act [sut runAsyncCode:^(NSArray *result) { hasCalledBack = YES; }]; // assert NSDate *timeout = [NSDate dateWithTimeIntervalSinceNow:0.1]; while([timeout timeIntervalSinceNow] > 0 && hasCalledBack == NO) { [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:timeout]; } XCTAssert(hasCalledBack, @"Test timed out"); }
Block-based code
![Page 53: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/53.jpg)
Block-based codeAlso we can use:
- (void)verifyWithDelay:(NSTimeInterval)delay { NSTimeInterval step = 0.01; while(delay > 0) { if([expectations count] == 0) break; NSDate* until = [NSDate dateWithTimeIntervalSinceNow:step]; [[NSRunLoop currentRunLoop] runUntilDate:until]; delay -= step; step *= 2; } [self verify]; }
OCMock
![Page 54: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/54.jpg)
CoreData
![Page 55: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/55.jpg)
CoreData
As long as you don't put business logic in your models, you don't have
to test them.
![Page 56: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/56.jpg)
CoreData
creates setters & getters in run-time
![Page 57: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/57.jpg)
CoreData
creates setters & getters in run-time
we can’t mock CoreData models
![Page 58: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/58.jpg)
CoreData
What can we do?
![Page 59: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/59.jpg)
CoreData- create protocol that has all model’s
properties defined
![Page 60: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/60.jpg)
CoreData- create protocol that has all model’s
properties defined - conform NSManagedObject to the
protocol
![Page 61: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/61.jpg)
CoreData- create protocol that has all model’s
properties defined - conform NSManagedObject to the
protocol - create NSObject model just for
testing, conforms to the protocol and @synthesize properties
![Page 62: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/62.jpg)
CoreData
Protocol
Model<Protocol> TestModel<Protocol>
![Page 63: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/63.jpg)
CoreDataProtocol
Model<Protocol> TestModel<Protocol>
![Page 64: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/64.jpg)
CoreData
Have a better solution?
![Page 65: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/65.jpg)
CoreDataCreate own CoreData stack for each
test-case
![Page 66: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/66.jpg)
- (void)setUp { [super setUp]; NSURL *modelURL = [[NSBundle mainBundle] URLForResource:@"SimpleInvoice" withExtension:@“momd"]; ! NSManagedObjectModel *mom = [[NSManagedObjectModel alloc] initWithContentsOfURL:modelURL]; ! NSPersistentStoreCoordinator *psc = [[NSPersistentStoreCoordinator alloc] initWithManagedObjectModel:mom]; ! XCTAssertNotNil([psc addPersistentStoreWithType:NSInMemoryStoreType configuration:nil URL:nil options:nil error:NULL], @"Should be able to add in-memory store”); ! _moc = [[NSManagedObjectContext alloc] init]; _moc.persistentStoreCoordinator = psc; }
CoreData
![Page 67: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/67.jpg)
- (void{ [ ! initWithContentsOfURL! initWithManagedObjectModel!!!!!!!! }
CoreData
- (void)setUp { !!!!!!!!!! XCTAssertNotNil([psc addPersistentStoreWithType:NSInMemoryStoreType configuration:nil URL:nil options:nil error:NULL], @"Should be able to add in-memory store”); !!!}
![Page 68: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/68.jpg)
CoreData
Advantages?
![Page 69: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/69.jpg)
CoreDataAdvantages?
- no additional classes
![Page 70: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/70.jpg)
CoreDataAdvantages?
- no additional classes - no dependence on external state
![Page 71: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/71.jpg)
CoreDataAdvantages?
- no additional classes - no dependence on external state - close approximation to the
application environment
![Page 72: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/72.jpg)
CoreDataAdvantages?
- no additional classes - no dependence on external state - close approximation to the
application environment - we are able to create base test
class with a stack and subclass it where we need
![Page 73: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/73.jpg)
CoreDataAdvantages?
- no additional classes
- no dependence on external state
- close approximation to the application environment
- we are able to create base test class with a stack and subclass it where we need
![Page 74: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/74.jpg)
- (void)testFullNameReturnsСorrectString { Person* ps; ps = [NSEntityDescription insertNewObjectForEntityForName:@"Person" inManagedObjectContext:_moc]; ps.firstName = @"Tom"; ps.lastName = @“Lol"; ! STAssertTrue([[ps fullName] isEqualToString:@"Lol Tom"], @"should have matched full name"); }
CoreData
![Page 75: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/75.jpg)
CoreData
- test model’s additional business-logic - test ManagedObjectModel for an
entity - create and use models as a mocks
![Page 76: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/76.jpg)
✅ UIViewControllers ✅ Block-based code ✅ CoreData
How to Test
![Page 77: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/77.jpg)
Video is coming!
Demo Codehttps://github.com/maksumko/ConverterApp"!
maksum.ko
contact me:
![Page 78: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/78.jpg)
Sourceshttp://www.amazon.com/Test-Driven-iOS-Development-Developers-Library/dp/0321774183 !http://www.objc.io/issue-1/testing-view-controllers.html http://www.silverbaytech.com/2013/02/25/ios-testing-part-3-testing-view-controller/ http://iosunittesting.com/unit-testing-view-controllers/ http://blog.carbonfive.com/2010/03/10/testing-view-controllers/ !http://iosunittesting.com/how-to-unit-test-completion-blocks/ !http://iosunittesting.com/unit-testing-core-data/ http://ashfurrow.com/blog/unit-testing-with-core-data-models http://www.sicpers.info/2010/06/template-class-for-unit-testing-core-data-entities/ http://iamleeg.blogspot.com/2010/01/unit-testing-core-data-driven-apps-fit.html
![Page 79: Unit Testing: Special Cases](https://reader033.vdocument.in/reader033/viewer/2022051323/549e73bbb37959664b8b45e6/html5/thumbnails/79.jpg)