Foreword |
|
xv | |
Preface |
|
xvii | |
|
|
|
|
3 | (16) |
|
What Are Unit Tests Anyway? |
|
|
4 | (1) |
|
Create a Place to Play with Tests |
|
|
4 | (2) |
|
Write Your First Assertion |
|
|
6 | (2) |
|
Add a Descriptive Message |
|
|
8 | (1) |
|
Avoid Conditionals in Tests |
|
|
9 | (1) |
|
Describe Objects upon Failure |
|
|
10 | (1) |
|
|
11 | (1) |
|
Test Equality with Optionals |
|
|
12 | (1) |
|
Fudge Equality with Doubles and Floats |
|
|
13 | (1) |
|
|
14 | (1) |
|
Choose the Right Assertion |
|
|
15 | (1) |
|
|
16 | (1) |
|
|
17 | (1) |
|
|
18 | (1) |
|
2 Manage Your Test Life Cycles |
|
|
19 | (16) |
|
|
19 | (2) |
|
|
21 | (1) |
|
Hook Up Tests to Production Code |
|
|
22 | (1) |
|
|
23 | (3) |
|
Observe Object Life Cycles to Learn the Phases of a Test |
|
|
26 | (2) |
|
The Wrong Way to Reduce Duplicate Test Code |
|
|
28 | (2) |
|
Learn How XCTest Manages Test Cases |
|
|
30 | (1) |
|
Use setup() and teardown() |
|
|
31 | (2) |
|
|
33 | (1) |
|
|
33 | (1) |
|
|
34 | (1) |
|
3 Measure Code Coverage and Add Tests |
|
|
35 | (18) |
|
|
35 | (1) |
|
|
36 | (1) |
|
Examine Code Coverage Results |
|
|
37 | (2) |
|
Drill into a Partially Covered Line |
|
|
39 | (1) |
|
Add Tests for Existing Code |
|
|
40 | (2) |
|
|
42 | (3) |
|
|
45 | (1) |
|
Cover Statements in a Sequence |
|
|
46 | (3) |
|
Avoid Percentage Targets, Embrace Forward Movement |
|
|
49 | (1) |
|
|
49 | (1) |
|
|
50 | (1) |
|
|
50 | (3) |
|
4 Take Control of Application Launch |
|
|
53 | (8) |
|
|
53 | (1) |
|
Observe the Default Behavior |
|
|
54 | (1) |
|
Learn About the Test Launch Sequence |
|
|
55 | (1) |
|
Bypass the Normal App Delegate |
|
|
55 | (2) |
|
Put Up with the Initial View Controller |
|
|
57 | (1) |
|
Tweak Your Testing App Delegate |
|
|
57 | (1) |
|
|
58 | (1) |
|
|
58 | (1) |
|
|
59 | (2) |
|
|
61 | (12) |
|
|
61 | (1) |
|
Set Up a Storyboard-Based View Controller for Experiments |
|
|
62 | (2) |
|
Load a Storyboard-Based View Controller |
|
|
64 | (2) |
|
Set Up a XIB-Based View Controller for Experiments |
|
|
66 | (1) |
|
Load a XIB-Based View Controller |
|
|
67 | (1) |
|
Set Up a Code-Based View Controller for Experiments |
|
|
68 | (1) |
|
Load a Code-Based View Controller |
|
|
69 | (2) |
|
|
71 | (1) |
|
|
71 | (1) |
|
|
72 | (1) |
|
6 Manage Difficult Dependencies |
|
|
73 | (22) |
|
Be Okay with Problem-Free Dependencies |
|
|
73 | (2) |
|
Identify Difficult Dependencies |
|
|
75 | (2) |
|
Create Boundaries to Isolate Dependencies |
|
|
77 | (1) |
|
|
77 | (3) |
|
Add Backdoors to Singletons You Own |
|
|
80 | (3) |
|
Subclass and Override: A Legacy Code Technique |
|
|
83 | (2) |
|
Inject Instances Through Initializers or Properties |
|
|
85 | (3) |
|
Inject Closures to Make New Instances |
|
|
88 | (2) |
|
|
90 | (1) |
|
|
91 | (1) |
|
|
91 | (4) |
|
Part II iOS Testing Tips and Techniques |
|
|
|
7 Testing Outlet Connections |
|
|
95 | (6) |
|
|
95 | (1) |
|
|
96 | (1) |
|
Check the Effectiveness of Failure Messages |
|
|
97 | (1) |
|
|
98 | (1) |
|
|
98 | (1) |
|
|
99 | (2) |
|
8 Testing Button Taps (Using Actions) |
|
|
101 | (6) |
|
Make a Place to Play with a Button |
|
|
101 | (1) |
|
|
102 | (2) |
|
Make a Test Helper for Button Taps |
|
|
104 | (1) |
|
|
105 | (1) |
|
|
105 | (1) |
|
|
106 | (1) |
|
|
107 | (8) |
|
|
107 | (1) |
|
Add the Helper Framework to the Project |
|
|
108 | (2) |
|
Test Alerts Using the Alert Verifier |
|
|
110 | (2) |
|
Move the SUT into the Test Fixture |
|
|
112 | (1) |
|
Add Tests for Alert Buttons |
|
|
112 | (1) |
|
|
113 | (1) |
|
|
114 | (1) |
|
|
114 | (1) |
|
10 Testing Navigation Between Screens |
|
|
115 | (14) |
|
|
115 | (1) |
|
Set Up Code-Based Navigation |
|
|
116 | (2) |
|
Set Up Segue-Based Navigation |
|
|
118 | (1) |
|
Test Code-Based Push Navigation |
|
|
119 | (3) |
|
Test Code-Based Modal Presentation |
|
|
122 | (2) |
|
Test Segue-Based Push Navigation |
|
|
124 | (2) |
|
Test Segue-Based Modal Navigation |
|
|
126 | (1) |
|
|
127 | (1) |
|
|
128 | (1) |
|
|
128 | (1) |
|
11 Testing UserDefaults (with Fakes) |
|
|
129 | (10) |
|
|
129 | (1) |
|
Isolate UserDefaults with Dependency Injection |
|
|
130 | (1) |
|
Extract a Protocol to Support Test Doubles |
|
|
131 | (2) |
|
|
133 | (1) |
|
|
134 | (3) |
|
|
137 | (1) |
|
|
137 | (1) |
|
|
138 | (1) |
|
12 Testing Network Requests (with Mocks) |
|
|
139 | (14) |
|
|
139 | (2) |
|
Isolate URLSession with Dependency Injection |
|
|
141 | (1) |
|
Extract a URLSession Protocol for Test Doubles |
|
|
141 | (2) |
|
|
143 | (1) |
|
|
144 | (2) |
|
Promote the Test Spy into a Mock Object |
|
|
146 | (2) |
|
Improve Mock Object Reporting |
|
|
148 | (3) |
|
|
151 | (1) |
|
|
151 | (1) |
|
|
152 | (1) |
|
13 Testing Network Responses (and Closures) |
|
|
153 | (16) |
|
|
153 | (2) |
|
|
155 | (3) |
|
Start with a Fresh Test Spy |
|
|
158 | (1) |
|
|
159 | (2) |
|
|
161 | (2) |
|
Keep Asynchronous Code in Its Closure |
|
|
163 | (1) |
|
|
164 | (3) |
|
|
167 | (1) |
|
|
168 | (1) |
|
|
168 | (1) |
|
14 Testing Text Fields (and Delegate Methods) |
|
|
169 | (16) |
|
|
169 | (3) |
|
|
172 | (1) |
|
Test Attributes and Wrangle UIKlt Descriptions |
|
|
173 | (4) |
|
|
177 | (3) |
|
|
180 | (3) |
|
|
183 | (1) |
|
|
184 | (1) |
|
|
184 | (1) |
|
|
185 | (8) |
|
|
185 | (2) |
|
|
187 | (4) |
|
|
191 | (1) |
|
|
191 | (1) |
|
|
192 | (1) |
|
16 Testing View Appearance (with Snapshots) |
|
|
193 | (16) |
|
|
193 | (3) |
|
Add FBSnapshotTestCase to a Test Target |
|
|
196 | (2) |
|
Set the Location for Reference Images |
|
|
198 | (1) |
|
|
199 | (2) |
|
See the Difference in a Snapshot Failure |
|
|
201 | (2) |
|
Manage Your Snapshot Tests |
|
|
203 | (2) |
|
|
205 | (1) |
|
|
206 | (1) |
|
|
206 | (3) |
|
Part III Using Your New Power |
|
|
|
17 Unleash the Power of Refactoring |
|
|
209 | (46) |
|
|
209 | (1) |
|
Lay Out the Views for Our Practice App |
|
|
210 | (3) |
|
Add the Code to Our Practice App |
|
|
213 | (7) |
|
Replace the Difficult Dependency with a Mock Object |
|
|
220 | (3) |
|
Write the First Tests of the Change Password View Controller |
|
|
223 | (4) |
|
|
227 | (2) |
|
|
229 | (11) |
|
Test the Text Field Delegate Method |
|
|
240 | (2) |
|
Refactor to Break Up a Long Function |
|
|
242 | (3) |
|
Extract a Method with Parameters |
|
|
245 | (6) |
|
Clean Up a Few More Places |
|
|
251 | (2) |
|
|
253 | (1) |
|
|
254 | (1) |
|
18 Refactoring: Moving to MWM |
|
|
255 | (18) |
|
|
255 | (1) |
|
Replace String Literals to Use a View Model |
|
|
256 | (3) |
|
Overwrite Storyboard Labels |
|
|
259 | (1) |
|
Respond to Changes in the View Model |
|
|
260 | (8) |
|
Move Logic into the View Model |
|
|
268 | (3) |
|
|
271 | (1) |
|
|
272 | (1) |
|
19 Refactoring: Moving to MVP |
|
|
273 | (24) |
|
|
273 | (1) |
|
|
274 | (1) |
|
Extract Methods into the View Commands Protocol |
|
|
275 | (4) |
|
Move a Function into the Presenter |
|
|
279 | (2) |
|
Remove the didSet Observer |
|
|
281 | (3) |
|
Use Refactoring Principles to Reparent a Swift Type |
|
|
284 | (2) |
|
Move Several Functions to the Presenter |
|
|
286 | (2) |
|
Extract Password Validation into Its Own Type |
|
|
288 | (5) |
|
Finish Up the Refactoring to MVP |
|
|
293 | (2) |
|
|
295 | (1) |
|
|
296 | (1) |
|
20 Test-Driven Development Beckons to You |
|
|
297 | (24) |
|
|
297 | (2) |
|
Make a New Place to Play with TDD |
|
|
299 | (1) |
|
Define the Requirements of the Tlme-of-Day Greeter |
|
|
299 | (1) |
|
Design the First Failing Test with Bare Production Code |
|
|
300 | (3) |
|
Make the First Test Pass with "Good Morning" |
|
|
303 | (1) |
|
Refactor the First Test to Make It More Expressive |
|
|
303 | (2) |
|
Repeat the TDD Steps for the Second Test |
|
|
305 | (2) |
|
Add Tests to Expand "Good Afternoon" |
|
|
307 | (1) |
|
|
308 | (1) |
|
Step Back to Refactor the Method as a Whole |
|
|
309 | (5) |
|
Add the Name to the Greeting |
|
|
314 | (3) |
|
|
317 | (1) |
|
|
318 | (3) |
Bibliography |
|
321 | (2) |
Index |
|
323 | |