Upload
jorge-ortiz
View
358
Download
3
Embed Size (px)
Citation preview
#7SUnitTest
Agenda
Evangelize about unit tests to seasoned programmers
Introduce them to everybody else
#7SUnitTest
Unit TestsProve correctness of different aspects of the public interface.
• Prove instead of intuition
• Define contract and assumptions
• Document the code
• Easier refactoring or change
Reusable code = code + tests
#7SUnitTest
Use Unit Testing Incrementally
You don’t have to write every unit test
Start with the classes that take care of the logic
• If mixed apply SOLID
The easier entry point are bugs
#7SUnitTest
Good & Bad NewsMost already available in Xcode / not doubles
Projects are created with
• test target
• a crappy example
⌘+U is your friend
Behaviors provide Pavlov reinforcement
XCTest is THE tool for the rest you are on your own
#7SUnitTest
The SUT
@interface Thermostat : NSObject
@property (strong, nonatomic) NSNumber *setpoint; @property (assign, nonatomic) BOOL imperialSystem;
- (NSString *) showSetpoint; - (void) increaseSetpoint; - (void) saveSetpoint;
@end
#7SUnitTest
Return
- (NSString *) showSetpoint { return [NSString stringWithFormat:@"%@ %@", self.setpoint, self.imperialSystem?@"F":@"C"]; }
#7SUnitTest
Test return
- (void) testSetpointIsShownWithTheRightUnits { // Arrange sut.setpoint = @23; sut.imperialSystem = NO;
// Act NSString *shownSetpoint = [sut showSetpoint];
// Assert XCTAssertEqualObjects(shownSetpoint, @"23 C"); }
#7SUnitTest
Test state
- (void) testIncreaseSetpointAddsOne { // Arrange sut.setpoint = @23;
// Act [sut increaseSetpoint];
// Assert XCTAssertEqualObjects(sut.setpoint, @24); }
#7SUnitTest
Behavior@interface Thermostat() @property (strong, nonatomic) NSUserDefaults *userDefaults; @end
@implementation Thermostat - (void) saveSetpoint { [self.userDefaults setObject:self.setpoint forKey:@"setpoint"]; }
- (NSUserDefaults *) userDefaults { if (_userDefaults == nil) { _userDefaults = [NSUserDefaults standardUserDefaults]; } return _userDefaults; } @end
#7SUnitTest
Create a Spy@interface UserDefaultsMock: NSUserDefaults
@property (assign, nonatomic) BOOL valueWasSet;
@end
@implementation UserDefaultsMock
- (void)setValue:(id)value forKey:(NSString *)key { self.valueWasSet = YES; }
@end
#7SUnitTest
Test behavior
- (void) testSetpointIsPersisted { // Arrange sut.setpoint = @23; UserDefaultsMock *userDefMock = [UserDefaultsMock new]; [sut setValue:userDefMock forKey:@"userDefaults"]; // Act [sut saveSetpoint];
// Assert XCTAssertTrue(userDefMock.valueWasSet); }
- (void) testSetpointIsPersisted { // Arrange sut.setpoint = @23; id userDefMock = [OCMockObject mockForClass:[NSUserDefaults class]]; OCMExpect([userDefMock setObject:sut.setpoint forKey:@"setpoint"]); [sut setValue:userDefMock forKey:@"userDefaults"]; // Act [sut saveSetpoint]; // Assert XCTAssertNoThrow([userDefMock verify]); }
Simulating and Testing Behavior
Stubs & Mocks
• Both are test doubles
• Stubs provide desired responses to the SUT
• Spies also expect certain behaviors
• Mocks include verification
#7SUnitTest
Dependency Injection
Control behavior of the dependencies
• Constructor
• Method overwriting
• Property injection:Lazy instantiation
Or use a DI framework (uncommon)
#7SUnitTest
Follow the rules
Test your code only
Only a level of abstraction
Only public methods
Only one assertion per test
Tests are independent of sequence or state
#7SUnitTest
Improve your coverage
Measure it
Assign priorities
Agree upon rules for your team/project
#7SUnitTest
And when I have too many tests?
Disable test cases
Run from command line
• xcodebuild
• xcpretty
#7SUnitTest
Evolve
Clean Architecture
TDD
Other tests: integration, ui, performance…
CI (OSX Server / Jenkins)