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-...
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 syste...
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 ...
Verifications
Types of Verifications
•Return Value

•State

•Behavior
Types of Verifications
SUT
Types of Verifications
SUT
Behavior 

(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.
SU...
State Verification
We inspect the state of the system under
test after it has been exercised and compare
it to the expected...
SUT
Behavior Verification
We capture the indirect outputs of the SUT
as they occur and compare them to the
expected behavio...
SUT
Behavior Verification
We capture the indirect outputs of the SUT
as they occur and compare them to the
expected behavio...
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 ...
XCTest
• Provided by Xcode

• New iOS application projects automatically include a unit
testing target

• Test classes do ...
XCTest
• Provided by Xcode

• New iOS application projects automatically include a unit
testing target

• Test classes do ...
XCTest
• Provided by Xcode

• New iOS application projects automatically include a unit
testing target

• Test classes do ...
XCTest Flow
Setup Tear DownTest
- (void)setUp
{
[super setUp];
// This method is called before the invocation of each test...
Test main actions:
• Arrange objects, creating and setting them up as necessary. 

• Act on an object. 

• Assert that som...
@interface ConverterModelTests : XCTestCase
{
ConverterModel* sut;
}
@end
!
@implementation ConverterModelTests
!
- (void)...
XCTest Asserts
• XCTFail (format…)
• XCTAssertNil (a1, format…)
• XCTAssertNotNil (a1, format…)
• XCTAssert (a1, format…)
...
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(someA...
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(someA...
Dependency Injection
Dependency Injection
is a software design pattern that
implements passing a service to a client,
rather than allowing a cl...
Constructor Injection
the dependencies are provided through a
class constructor
- (id)initWithNotificationCenter:(NSNotifi...
Setter Injection
the client exposes a setter method that the
injector uses to inject the dependency
@property (nonatomic, ...
Dependency Injection
providing an instance variable for dependency
- (void)viewDidLoad
{
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(someA...
- (id)initWithNotificationCenter:(NSNotificationCenter *)notificationCenter
{
self = [super init];
if(self)
{
_notificatio...
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 i...
Test
Mocks
SUT communicates with the mock object, and all
communication is recorded in the mock. The test
uses the mock to...
Test
Stubs
Returns specified result for a message, stubs
can’t fail the test.
SUT Stub
Communicate
Assert
@interface ConverterViewController : UIViewController
!
@property (nonatomic, weak) NSNotificationCenter* notificationCent...
@interface ConverterViewController : UIViewController
!
@property (nonatomic, weak) NSNotificationCenter* notificationCent...
What we need?
•an object that responds to
addObserver:selector:name:object:

•possibility to record a call

•check for not...
@interface FakeNotificationCenter : NSObject
{
BOOL _hasCalled;
}
@property (nonatomic, strong) NSString* expectedName;
!
...
- (void)testViewDidLoadAddsObserverForSomeNotification
{
// Arrange
FakeNotificationCenter* fake = [FakeNotificationCenter...
- (void)testViewDidLoadAddsObserverForSomeNotification
{
// Arrange
FakeNotificationCenter* fake = [FakeNotificationCenter...
- (void)testViewDidLoadAddsObserverForSomeNotification
{
// Arrange
FakeNotificationCenter* fake = [FakeNotificationCenter...
OCMock
OCMock Provides
•stub objects that return pre-determined values
for specific method invocations

•dynamic mocks that can be...
Mocks
// Creates a mock object that can be used as if it were an instance of
// SomeClass.
id mock = [OCMockObject mockFor...
Stubs
// Tells the mock object that when someMethod: is called with
// someArgument it should return aValue.
[[[mock stub]...
@interface ConverterViewController : UIViewController
!
@property (nonatomic, weak) NSNotificationCenter* notificationCent...
- (void)testViewDidLoadAddsObserver
{
// Arrange
id mock = [OCMockObject mockForClass:[NSNotificationCenter class]];
[[moc...
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

• Is...
How to start with Existing Project
• All developers in team must write and run tests

• Start with warnings and bugs

• Is...
How to start with Existing Project
• All developers in team must write and run tests

• Start with warnings and bugs

• Is...
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-Develop...
Questions?
Upcoming SlideShare
Loading in...5
×

Unit Tesing in iOS

649

Published on

iOS Practice Leaders Community Meet-up.

“Unit Testing in iOS” by Maxim Koshtenko

- why we need tests and what their use in applications’ developing on a project is;
- how one should and should not test source code;
- review of some of the most popular tools which make test-writing easier;
- how to switch to unit-testing on a project which already exists.

Published in: Software, Technology, Education
0 Comments
4 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total Views
649
On Slideshare
0
From Embeds
0
Number of Embeds
3
Actions
Shares
0
Downloads
20
Comments
0
Likes
4
Embeds 0
No embeds

No notes for slide

Transcript of "Unit Tesing in iOS"

  1. 1. Unit Testing
  2. 2. Unit Testing What Is Testing For? 
  3. 3. Unit Testing When Should Software Be Tested? What Is Testing For? 
  4. 4. What Is Testing For?
  5. 5. What Is Testing For? Testing can show that the product works!
  6. 6. When Should Software Be Tested?
  7. 7. Waterfall project management process
  8. 8. Waterfall project management process Requirements
  9. 9. Waterfall project management process Requirements Specification
  10. 10. Waterfall project management process Requirements Development Specification
  11. 11. Waterfall project management process Requirements Test Development Specification
  12. 12. Waterfall project management process Requirements Test Development Specification Deployment
  13. 13. 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
  14. 14. When Should Software Be Tested?
  15. 15. When Should Software Be Tested? Software should be tested all the time!
  16. 16. Unit Testing
  17. 17. What is Unit Test? Unit tests are small pieces of code that test the behavior of other code.
  18. 18. 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.
  19. 19. Properties of a Good Unit Test
  20. 20. A good unit test: is able to be fully automated
  21. 21. A good unit test: Tests a single logical concept in the system
  22. 22. A good unit test: Consistently returns the same result (no random numbers, save those for integration tests)
  23. 23. A good unit test: is Maintainable and order-independent
  24. 24. A good unit test: is Independent
  25. 25. A good unit test: Runs fast
  26. 26. A good unit test: is Readable
  27. 27. A good unit test: is Trustworthy (when you see its result, you don’t need to debug the code just to be sure)
  28. 28. 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
  29. 29. Verifications
  30. 30. Types of Verifications •Return Value •State •Behavior
  31. 31. Types of Verifications SUT
  32. 32. Types of Verifications SUT Behavior (Indirect Outputs) DOC
  33. 33. Types of Verifications SUTSetup Exercise Verify Tear Down Behavior (Indirect Outputs) DOC
  34. 34. 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
  35. 35. 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
  36. 36. 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
  37. 37. 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
  38. 38. XCTest
  39. 39. XCTest • Provided by Xcode
  40. 40. XCTest • Provided by Xcode • New iOS application projects automatically include a unit testing target
  41. 41. XCTest • Provided by Xcode • New iOS application projects automatically include a unit testing target • Test classes do not have a header file
  42. 42. 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
  43. 43. 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
  44. 44. 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
  45. 45. 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__); }
  46. 46. 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"); }
  47. 47. @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
  48. 48. 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…)
  49. 49. - (void)viewDidLoad { [super viewDidLoad]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(someAction:) name:kSomeNotification object:nil]; }
  50. 50. - (void)viewDidLoad { [super viewDidLoad]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(someAction:) name:kSomeNotification object:nil]; } - (void)testViewDidLoadAddsObserverForSomeNotification { // Arrange // Act // Assert ! }
  51. 51. Dependency Injection
  52. 52. 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.
  53. 53. Constructor Injection the dependencies are provided through a class constructor - (id)initWithNotificationCenter:(NSNotificationCenter *)notificationCenter
  54. 54. Setter Injection the client exposes a setter method that the injector uses to inject the dependency @property (nonatomic, weak) NSUserDefaults* userDefaults;
  55. 55. Dependency Injection providing an instance variable for dependency
  56. 56. - (void)viewDidLoad { [super viewDidLoad]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(someAction:) name:kSomeNotification object:nil]; } Dependency - (void)testViewDidLoadAddsObserverForSomeNotification { // Arrange // Act // Assert ! }
  57. 57. - (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
  58. 58. Mocks
  59. 59. is a fake object in the system that verifies the object under test interacted as expected with the fake object. Mock Object
  60. 60. 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 SUT Behavior Verification Setup Exercise Verify Tear Down Behavior (Indirect Outputs) Fake Verify
  61. 61. 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 Mock Communicate Assert
  62. 62. Test Stubs Returns specified result for a message, stubs can’t fail the test. SUT Stub Communicate Assert
  63. 63. @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
  64. 64. @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
  65. 65. What we need? •an object that responds to addObserver:selector:name:object: •possibility to record a call •check for notification’s name •verification
  66. 66. @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
  67. 67. - (void)testViewDidLoadAddsObserverForSomeNotification { // Arrange FakeNotificationCenter* fake = [FakeNotificationCenter new]; fake.expectedName = kSomeNotification; sut.notificationCenter = (id)fake; // Assert [fake verify]; } ! How can we use it?
  68. 68. - (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?
  69. 69. - (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?
  70. 70. OCMock
  71. 71. 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
  72. 72. 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];
  73. 73. 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]];
  74. 74. @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
  75. 75. - (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
  76. 76. Legacy Code?
  77. 77. How to start with Existing Project • All developers in team must write and run tests
  78. 78. How to start with Existing Project • All developers in team must write and run tests • Start with warnings and bugs
  79. 79. How to start with Existing Project • All developers in team must write and run tests • Start with warnings and bugs • Isolate modules and classes
  80. 80. 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
  81. 81. 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
  82. 82. Demo Code https://github.com/maksumko/ConverterApp ! maksum.ko
  83. 83. 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
  84. 84. Questions?
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×