An iOS developer’s guide to unit testing

Arya MirΚινητά – Ασύρματες Τεχνολογίες

12 Οκτ 2011 (πριν από 6 χρόνια και 10 μέρες)

926 εμφανίσεις

An iOS developer’s guide to unit testing

STAssertTrue
(thisThing.state
== NSONState,
@”
Is this thing on?
”);
An iOS developer’s guide to unit testing
Software engineering:
goals
Software engineering:
goals

Make money (sometimes)
Software engineering:
goals

Make money (sometimes)

…by making software that the customer
wants
Software engineering:
goals

Make money (sometimes)

…by making software that the customer
wants

Satisfies the customer’s requirements
Software engineering:
goals

Make money (sometimes)

…by making software that the customer
wants

Satisfies the customer’s requirements

Without costing too much to make
Testing: goals

validate code
behaviour

discover defects

verify fixes

detect regressions
Cost
Time Detected
Time Detected
Time Detected
Time Detected
Time Detected
Time
introduced
Requirements
Architecture
Construction
Requirements
Architecture
Construction
System
Test
After
Release
1
3
5-10
10
10-100
-
1
10
15
25-100
-
-
1
10
10-25
Testing: goals

validate code
behaviour

discover defects

verify fixes

detect regressions
Cost
Time Detected
Time Detected
Time Detected
Time Detected
Time Detected
Time
introduced
Requirements
Architecture
Construction
Requirements
Architecture
Construction
System
Test
After
Release
1
3
5-10
10
10-100
-
1
10
15
25-100
-
-
1
10
10-25
Unit Testing
The testing landscape
Class
Component
System
White Box
Grey Box
Black Box
Beta/Acceptance Testing
Integration Testing
Unit testing (undirected)
Static Analysis, Debugging
GUI Testing
System Test
Source Audit
Pen/fuzz Testing
The testing landscape
Class
Component
System
White Box
Grey Box
Black Box
Beta/Acceptance Testing
Integration Testing
Unit testing (undirected)
TDD
Static Analysis, Debugging
GUI Testing
System Test
Source Audit
Pen/fuzz Testing
TDD - what it achieves
TDD - what it achieves

Imposes black-box thinking for the
developer
TDD - what it achieves

Imposes black-box thinking for the
developer

Guides design and implementation
TDD - what it achieves

Imposes black-box thinking for the
developer

Guides design and implementation

YAGNI
TDD - what it achieves

Imposes black-box thinking for the
developer

Guides design and implementation

YAGNI

Provides a safety net for future
development
TDD - what it achieves

Imposes black-box thinking for the
developer

Guides design and implementation

YAGNI

Provides a safety net for future
development

Assists accurate planning
Find bugs before…
© 2009 Microsoft
…your customers do
TDD ! [bullet
silverColor]
TDD ! [bullet
silverColor]

Can’t ensure the developer understood
requirements
TDD ! [bullet
silverColor]

Can’t ensure the developer understood
requirements

Or that the requirements remained static
TDD ! [bullet
silverColor]

Can’t ensure the developer understood
requirements

Or that the requirements remained static

Doesn’t guarantee successful integration
TDD ! [bullet
silverColor]

Can’t ensure the developer understood
requirements

Or that the requirements remained static

Doesn’t guarantee successful integration

Takes time (mainly to write)
TDD ! [bullet
silverColor]

Can’t ensure the developer understood
requirements

Or that the requirements remained static

Doesn’t guarantee successful integration

Takes time (mainly to write)

Must actually be run to add value
How TDD Works
How TDD Works
RED
How TDD Works
RED
GREEN
How TDD Works
RED
GREEN
REFACTOR
What do I test?
What do I test?

Anything, within reason

Mustn’t take too long to run the tests

Shouldn’t depend on the environment

database, filesystem, network

…not that those tests aren’t important
What do I test?

Anything, within reason

Mustn’t take too long to run the tests

Shouldn’t depend on the environment

database, filesystem, network

…not that those tests aren’t important

Evaluate risk

known-buggy classes

“hard” code
When do I test?

Whenever you make a change

Whenever you want to build
Test Design
- (
void
)setUp {

gregorianCalendar
= [[
NSCalendar

alloc
]
initWithCalendarIdentifier
:
NSGregorianCalendar
];

comps
= [[
NSDateComponents

alloc
]
init
];
}
- (
void
)tearDown {
[
gregorianCalendar

release
];

gregorianCalendar
=
nil
;
[
comps

release
];

comps
=
nil
;
}
Common stuff here
- (
void
)testDatesOnTheSameDayAreConsideredSame {
//...
}
- (
void
)testCloseDatesOnSeparateDaysAreNotSame {
//...
}
- (
void
)testSameDayInDifferentYearsAreNotTheSame {
//...
}
These all independent
short, readable,
fast
#import
<SenTestingKit/SenTestingKit.h>
@interface
DateComparisonTests : SenTestCase {
One (or more) per class
Test Design
must be
repeatable
Source:
http://xkcd.com/221/
Testable code
Testable code

Small, focussed classes, that contain…
Testable code

Small, focussed classes, that contain…

Short methods, each with obvious effect
Testable code

Small, focussed classes, that contain…

Short methods, each with obvious effect

Any side-effects are few and easy to predict
Testable code

Small, focussed classes, that contain…

Short methods, each with obvious effect

Any side-effects are few and easy to predict

Helper data passed in, not discovered
Testable code

Small, focussed classes, that contain…

Short methods, each with obvious effect

Any side-effects are few and easy to predict

Helper data passed in, not discovered

Low “cyclomatic complexity”
Testable code

Small, focussed classes, that contain…

Short methods, each with obvious effect

Any side-effects are few and easy to predict

Helper data passed in, not discovered

Low “cyclomatic complexity”
i.e. an end to
@interface GodClass : UIViewController
OCUnit and Xcode 3
OCUnit and Xcode 4
OCUnit and Xcode 4
Boo.
Yay!
The competition…
The competition…
OCUnit and the Device
Source:
http://developer.apple.com/iphone/library/documentation/Xcode/Conceptual/
iphone_development/135-Unit_Testing_Applications/unit_testing_applications.html
Enter GHUnit
http://github.com/gabriel/gh-unit
Enter GHUnit
http://github.com/gabriel/gh-unit
Fakes and Mocks
- (
IBAction
)removeTune: (
id
)sender
{
[
self
.
tunesArrayController

remove
: sender];
[
self

destroyAttachedWindow
];
}
Fakes and Mocks
- (
IBAction
)removeTune: (
id
)sender
{
[
self
.
tunesArrayController

remove
: sender];
[
self

destroyAttachedWindow
];
}
Fake sender
Fakes and Mocks
- (
IBAction
)removeTune: (
id
)sender
{
[
self
.
tunesArrayController

remove
: sender];
[
self

destroyAttachedWindow
];
}
Fake sender
Mock array controller
Bibble…Biblob…List of
books
Bibble…Biblob…List of
books
Bibble…Biblob…List of
books
Bibble…Biblob…List of
books
Bibble…Biblob…List of
books
Bibble…Biblob…List of
books
iamleeg
iamleeg