unit tesing in ios
Post on 06-May-2015
563 Views
Preview:
DESCRIPTION
TRANSCRIPT
Unit Testing
Unit Testing
What Is Testing For?
Unit Testing
When Should Software Be Tested?
What Is Testing For?
What Is Testing For?
What Is Testing For?
Testing can show that the product works!
When Should Software Be Tested?
Waterfall project management process
Waterfall project management process
Requirements
Waterfall project management process
Requirements
Specification
Waterfall project management process
Requirements
Development
Specification
Waterfall project management process
Requirements
Test
Development
Specification
Waterfall project management process
Requirements
Test
Development
Specification
Deployment
Cost of Bugs Time Detected
Time Introduced Requirements Architecture Coding System Test Post-
Release
Requirements 1 3 5-10 10 10-100
Architecture - 1 10 15 25-100
Coding - - 1 10 10-25
Cost of Fixing Bugs Found at Different Stages of the Software Development Process
When Should Software Be Tested?
When Should Software Be Tested?
Software should be tested all the time!
Unit Testing
What is Unit Test?
Unit tests are small pieces of code that test the behavior of other code.
A test is not a unit test if:
• It talks to the database
• It communicates across the network
• It touches the file system
• It can't run at the same time as any of your other unit tests
• You have to do special things to your environment (such as editing config files) to run it.
Properties of a Good Unit Test
A good unit test:
is able to be fully automated
A good unit test:
Tests a single logical concept in the system
A good unit test:
Consistently returns the same result (no random numbers, save those for integration
tests)
A good unit test:
is Maintainable and order-independent
A good unit test:
is Independent
A good unit test:
Runs fast
A good unit test:
is Readable
A good unit test:
is Trustworthy (when you see its result, you don’t need to debug the code just to be sure)
A good unit test is:• Able to be fully automated
• Tests a single logical concept in the system
• Consistently returns the same result
• Maintainable and order-independent
• Independent
• Runs fast
• Readable
• Trustworthy
Verifications
Types of Verifications
•Return Value
•State
•Behavior
Types of Verifications
SUT
Types of Verifications
SUTBehavior (Indirect Outputs)
DOC
Types of Verifications
SUTSetup
Exercise
Verify
Tear Down
Behavior (Indirect Outputs)
DOC
Return Value Verification
We inspect the value returned from the system under test and compare it to the
expected state.
SUTSetup
Exercise
Verify
Tear Down
Behavior (Indirect Outputs)
DOC
State Verification
We inspect the state of the system under test after it has been exercised and compare
it to the expected state.
SUTSetup
Exercise
Verify
Tear Down
Behavior (Indirect Outputs)
DOC
State
SUT
Behavior Verification
We capture the indirect outputs of the SUT as they occur and compare them to the
expected behavior.
Setup
Exercise
Verify
Tear Down
Behavior (Indirect Outputs)
DOC
SUT
Behavior Verification
We capture the indirect outputs of the SUT as they occur and compare them to the
expected behavior.
Setup
Exercise
Verify
Tear Down
Behavior (Indirect Outputs)
Fake
Verify
XCTest
XCTest• Provided by Xcode
XCTest• Provided by Xcode
• New iOS application projects automatically include a unit testing target
XCTest• Provided by Xcode
• New iOS application projects automatically include a unit testing target
• Test classes do not have a header file
XCTest• Provided by Xcode
• New iOS application projects automatically include a unit testing target
• Test classes do not have a header file
• It’s not necessary to add application’s source files to the XCTest Target
XCTest• Provided by Xcode
• New iOS application projects automatically include a unit testing target
• Test classes do not have a header file
• It’s not necessary to add application’s source files to the XCTest Target
• Each test case is a method with prefix test
XCTest• Provided by Xcode
• New iOS application projects automatically include a unit testing target
• Test classes do not have a header file
• It’s not necessary to add application’s source files to the XCTest Target
• Each test case is a method with prefix test
• Xcode 5 allows to run tests from the editor
XCTest Flow
Setup Tear DownTest
- (void)setUp { [super setUp]; // This method is called before the invocation of each test method in the class. } !- (void)tearDown { // This method is called after the invocation of each test method in the class. [super tearDown]; } !- (void)testExample { XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); }
Test main actions:• Arrange objects, creating and setting them up as necessary.
• Act on an object.
• Assert that something is as expected.
!- (void)testMakeConversionWithModeMilesToKilometers { // Arrange sut.value = @(1); // Act [sut makeConversionWithMode:ConverterModeMilesToKm]; // Assert XCTAssertTrue([sut.text isEqualToString:@"1.609344"], @"should convert from miles to kilometers"); }
@interface ConverterModelTests : XCTestCase { ConverterModel* sut; } @end !@implementation ConverterModelTests !- (void)setUp { [super setUp]; sut = [ConverterModel new]; } !- (void)tearDown { sut = nil; [super tearDown]; } !- (void)testMakeConversionWithModeMilesToKilometers { // Arrange sut.value = @(1); // Act [sut makeConversionWithMode:ConverterModeMilesToKm]; // Assert XCTAssertTrue([sut.text isEqualToString:@"1.609344"], @"should convert from miles to kilometers"); } !@end
XCTest Asserts• XCTFail (format…)
• XCTAssertNil (a1, format…)
• XCTAssertNotNil (a1, format…)
• XCTAssert (a1, format…)
• XCTAssertTrue (a1, format…)
• XCTAssertFalse (a1, format…)
• XCTAssertEqualObjects (a1, a2, format…)
• XCTAssertEquals (a1, a2, format…)
• XCTAssertEqualsWithAccuracy (a1, a2, accuracy, format…)
• XCTAssertThrows (expression, format…)
• XCTAssertThrowsSpecific (expression, exception, format…)
• XCTAssertThrowsSpecificNamed (expression, exception, name, format…)
• XCTAssertNoThrow (expression, format…)
• XCTAssertNoThrowSpecific (expression, exception, format…)
• XCTAssertNoThrowSpecificNamed (expression, exception, name, format…)
- (void)viewDidLoad { [super viewDidLoad]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(someAction:) name:kSomeNotification object:nil]; }
- (void)viewDidLoad { [super viewDidLoad]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(someAction:) name:kSomeNotification object:nil]; }
- (void)testViewDidLoadAddsObserverForSomeNotification { // Arrange // Act // Assert !}
Dependency Injection
Dependency Injection
is a software design pattern that implements passing a service to a client, rather than allowing a client to build or find the service.
Constructor Injection
the dependencies are provided through a class constructor
- (id)initWithNotificationCenter:(NSNotificationCenter *)notificationCenter
Setter Injection
the client exposes a setter method that the injector uses to inject the dependency
@property (nonatomic, weak) NSUserDefaults* userDefaults;
Dependency Injection
providing an instance variable for dependency
- (void)viewDidLoad { [super viewDidLoad]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(someAction:) name:kSomeNotification object:nil]; }
Dependency
- (void)testViewDidLoadAddsObserverForSomeNotification { // Arrange // Act // Assert !}
- (id)initWithNotificationCenter:(NSNotificationCenter *)notificationCenter { self = [super init]; if(self) { _notificationCenter = notificationCenter; } return self; } !!- (void)viewDidLoad { [super viewDidLoad]; [_notificationCenter addObserver:self selector:@selector(someAction:) name:kSomeNotification object:nil]; }
Inject Dependency
Mocks
is a fake object in the system that verifies the object under test interacted as expected with the fake object.
Mock Object
It is common in unit tests to mock or stub collaborators of the system under test so that the test is independent of the implementation of the collaborators.
Mock Object
SUTBehavior Verification
Setup
Exercise
Verify
Tear Down
Behavior (Indirect Outputs)
Fake
Verify
Test
Mocks
SUT communicates with the mock object, and all communication is recorded in the mock. The test uses the mock to verify that the test passes.
SUT MockCommunicate
Assert
Test
Stubs
Returns specified result for a message, stubs can’t fail the test.
SUT StubCommunicate
Assert
@interface ConverterViewController : UIViewController !@property (nonatomic, weak) NSNotificationCenter* notificationCenter; !@end !!@implementation ConverterViewController !- (void)viewDidLoad { [super viewDidLoad]; [_notificationCenter addObserver:self selector:@selector(someAction:) name:kSomeNotification object:nil]; } !@end
Injected Dependency
@interface ConverterViewController : UIViewController !@property (nonatomic, weak) NSNotificationCenter* notificationCenter; !@end !!@implementation ConverterViewController !- (void)viewDidLoad { [super viewDidLoad]; [_notificationCenter addObserver:self selector:@selector(someAction:) name:kSomeNotification object:nil]; } !@end
Injected Dependency
Replace with a mock
What we need?
•an object that responds to addObserver:selector:name:object:
•possibility to record a call
•check for notification’s name
•verification
@interface FakeNotificationCenter : NSObject { BOOL _hasCalled; } @property (nonatomic, strong) NSString* expectedName; !- (void)addObserver:(id)observer selector:(SEL)aSelector name:(NSString *)aName object:(id)anObject; - (void)verify; !@end !!@implementation FakeNotificationCenter !- (void)addObserver:(id)observer selector:(SEL)aSelector name:(NSString *)aName object:(id)anObject { _hasCalled = [_expectedName isEqualToString:aName]; } !- (void)verify { NSAssert(_hasCalled, @"expected method was not called with specified parameters"); } !@end
What we can do
- (void)testViewDidLoadAddsObserverForSomeNotification { // Arrange FakeNotificationCenter* fake = [FakeNotificationCenter new]; fake.expectedName = kSomeNotification; sut.notificationCenter = (id)fake; // Assert [fake verify]; } !
How can we use it?
- (void)testViewDidLoadAddsObserverForSomeNotification { // Arrange FakeNotificationCenter* fake = [FakeNotificationCenter new]; fake.expectedName = kSomeNotification; sut.notificationCenter = (id)fake; ! // Assert [fake verify]; } !-[ConverterViewControllerTests testViewDidLoadAddsObserver] failed: expected method was not called with specified parameters
How can we use it?
- (void)testViewDidLoadAddsObserverForSomeNotification { // Arrange FakeNotificationCenter* fake = [FakeNotificationCenter new]; fake.expectedName = kSomeNotification; sut.notificationCenter = (id)fake; ! // Act [sut viewDidLoad]; // Assert [fake verify]; }
How can we use it?
OCMock
OCMock Provides
•stub objects that return pre-determined values for specific method invocations
•dynamic mocks that can be used to verify interaction patterns
•partial mocks to overwrite selected methods of existing objects
Mocks// Creates a mock object that can be used as if it were an instance of // SomeClass. id mock = [OCMockObject mockForClass:[SomeClass class]]; !!// Tells the mock object that someMethod: should be called with an argument // that is equal to someArgument. [[mock expect] someMethod:someArgument]; !// After this setup the functionality under test should be invoked // followed by [mock verify]; !!// When a method is called on a mock object that has not been set up with // either expect or stub the mock object will raise an exception. This // fail-fast mode can be turned off by creating a "nice" mock: id mock = [OCMockObject niceMockForClass:[SomeClass class]]; !// While nice mocks will simply ignore all unexpected methods it is // possible to disallow specific methods: [[mock reject] someMethod];
Stubs // Tells the mock object that when someMethod: is called with // someArgument it should return aValue.
[[[mock stub] andReturn:aValue] someMethod:someArgument]; !!! // It is not possible to pass primitive types directly. [[[mock stub] andReturnValue:@YES] aMethodReturnABoolean:someArgument]; !! // The mock object can also throw an exception or post a notification // when a method is called [[[mock stub] andThrow:anException] someMethod:someArgument]; [[[mock stub] andPost:aNotification] someMethod:someArgument]; !!! // If Objective-C blocks are available a block can be used to handle the // invocation and set up a return value void (^theBlock)(NSInvocation *) = ^(NSInvocation *invocation) { /* code that reads and modifies the invocation object */ }; [[[mock stub] andDo:theBlock] someMethod:[OCMArg any]];
@interface ConverterViewController : UIViewController !@property (nonatomic, weak) NSNotificationCenter* notificationCenter; !@end !!@implementation ConverterViewController !- (void)viewDidLoad { [super viewDidLoad]; [_notificationCenter addObserver:self selector:@selector(someAction:) name:kSomeNotification object:nil]; } !@end
Injected Dependency
- (void)testViewDidLoadAddsObserver { // Arrange id mock = [OCMockObject mockForClass:[NSNotificationCenter class]]; [[mock expect] addObserver:sut selector:[OCMArg anySelector] name:kConverterModelDidUpdateNotification object:OCMOCK_ANY]; sut.notificationCenter = mock; ! // Act [sut viewDidLoad]; // Assert [mock verify]; }
How we test this with OCMock
Legacy Code?
How to start with Existing Project
• All developers in team must write and run tests
How to start with Existing Project
• All developers in team must write and run tests
• Start with warnings and bugs
How to start with Existing Project
• All developers in team must write and run tests
• Start with warnings and bugs
• Isolate modules and classes
How to start with Existing Project
• All developers in team must write and run tests
• Start with warnings and bugs
• Isolate modules and classes
• Don’t miss refactoring
How to start with Existing Project
• All developers in team must write and run tests
• Start with warnings and bugs
• Isolate modules and classes
• Don’t miss refactoring
• Increase test-coverage step-by-step with new
functionality
Demo Code
https://github.com/maksumko/ConverterApp
!
maksum.ko
Sources
http://www.amazon.com/Art-Unit-Testing-Examples-Net/dp/1933988274
!
http://www.amazon.com/Test-Driven-iOS-Development-Developers-Library/dp/0321774183
!
http://www.amazon.com/Growing-Object-Oriented-Software-Guided-Tests/dp/0321503627
!
http://martinfowler.com/articles/mocksArentStubs.html
Questions?
top related