About the Author |
|
xiii | |
About the Technical Reviewer |
|
xv | |
Acknowledgments |
|
xvii | |
A Gift for You |
|
xix | |
|
Chapter 1 Why Test-Driven Development? |
|
|
1 | (12) |
|
|
1 | (1) |
|
Manual Testing Is Inefficient |
|
|
2 | (1) |
|
Code That Checks Other Code |
|
|
3 | (4) |
|
From Writing Tests to Writing Tests First |
|
|
7 | (3) |
|
From Writing Tests First to Test-Driven Development |
|
|
10 | (1) |
|
|
11 | (1) |
|
|
12 | (1) |
|
Chapter 2 XCTest Introduction |
|
|
13 | (14) |
|
The Xcode Unit Test Target |
|
|
13 | (3) |
|
XCTestCase and Equality Assertion |
|
|
16 | (2) |
|
|
18 | (1) |
|
|
18 | (2) |
|
Expectations for Asynchronous Code |
|
|
20 | (2) |
|
|
22 | (3) |
|
|
25 | (2) |
|
Chapter 3 Getting Started with Test-Driven Development |
|
|
27 | (16) |
|
|
28 | (1) |
|
Fake It...Till You Make It |
|
|
29 | (3) |
|
|
32 | (2) |
|
First Make the Test Pass; then Make the Code Clean |
|
|
34 | (4) |
|
The Compiler Is Part of the TDD Process |
|
|
38 | (1) |
|
|
39 | (2) |
|
|
41 | (2) |
|
Chapter 4 Test-Driven Development in the Real World |
|
|
43 | (26) |
|
|
43 | (1) |
|
|
44 | (1) |
|
Partition Problem and Solve Sequentially |
|
|
45 | (2) |
|
|
47 | (16) |
|
Use the Strictest Assertions Possible |
|
|
52 | (3) |
|
Use the Clearest Assertion Possible |
|
|
55 | (1) |
|
Don't Let the Tests Crash |
|
|
56 | (4) |
|
|
60 | (2) |
|
Red, Green, and Don't Forget Refactor |
|
|
62 | (1) |
|
|
63 | (4) |
|
|
67 | (1) |
|
|
68 | (1) |
|
Chapter 5 Changing Tests with Fixtures |
|
|
69 | (10) |
|
The Hidden Cost of Source Changes |
|
|
70 | (1) |
|
|
71 | (2) |
|
Fixtures vs. Convenience Initializers |
|
|
73 | (1) |
|
Fixtures Make the Test Actors Explicit |
|
|
74 | (2) |
|
|
76 | (1) |
|
Introduce Fixtures As Early As Possible |
|
|
76 | (1) |
|
|
77 | (1) |
|
|
77 | (1) |
|
|
78 | (1) |
|
Chapter 6 Testing Static SwiftUI Views |
|
|
79 | (18) |
|
The Problem with Presentation Logic in the View |
|
|
79 | (2) |
|
Decouple Presentation Logic from the View Implementation |
|
|
81 | (1) |
|
Preparatory Refactor: Reduce the Working Surface Area |
|
|
82 | (1) |
|
|
83 | (3) |
|
Using the ViewModel in the View |
|
|
86 | (1) |
|
|
87 | (1) |
|
|
88 | (6) |
|
|
94 | (1) |
|
|
94 | (3) |
|
Chapter 7 Testing Dynamic SwiftUI Views |
|
|
97 | (22) |
|
How SwiftUI and Combine Make Seamless View Updates Possible |
|
|
98 | (1) |
|
Make the ViewModel Stream Updates with ObservableObject |
|
|
99 | (6) |
|
The Dependency Inversion Principle |
|
|
105 | (6) |
|
Decouple the ViewModel from the Data Fetching with DIP |
|
|
108 | (3) |
|
How to Test Async Updates of @Published Properties |
|
|
111 | (4) |
|
|
115 | (1) |
|
|
116 | (1) |
|
|
117 | (2) |
|
Chapter 8 Testing Code Based on Indirect Inputs |
|
|
119 | (14) |
|
|
120 | (11) |
|
Make Error Handling Explicit with Result |
|
|
124 | (7) |
|
|
131 | (1) |
|
|
132 | (1) |
|
Chapter 9 Testing JSON Decoding |
|
|
133 | (18) |
|
|
137 | (1) |
|
|
138 | (4) |
|
|
142 | (2) |
|
Is Testing JSON Decoding Worth It? |
|
|
144 | (4) |
|
|
148 | (1) |
|
|
149 | (1) |
|
|
150 | (1) |
|
Chapter 10 Testing Network Code |
|
|
151 | (16) |
|
Why You Shouldn't Make Network Requests in Your Unit Tests |
|
|
152 | (5) |
|
How to Decouple the Unit Tests from the Network |
|
|
157 | (3) |
|
Simulate Network Requests Using a Stub |
|
|
160 | (4) |
|
A Third-Party Alternative |
|
|
163 | (1) |
|
|
164 | (1) |
|
|
165 | (1) |
|
|
166 | (1) |
|
Chapter 11 Injecting Dependencies with @EnvironmentObject |
|
|
167 | (18) |
|
How Dependency Injection Keeps Each Test Isolated |
|
|
170 | (14) |
|
Dependency Injection vs. Directly Accessing Shared Instances |
|
|
176 | (1) |
|
Dependency Injection with @EnvironmentObject |
|
|
177 | (4) |
|
The Downside of @EnvironmentObject |
|
|
181 | (1) |
|
@EnvironmentObject vs. Directly Accessing Shared Instances |
|
|
182 | (2) |
|
|
184 | (1) |
|
|
184 | (1) |
|
Chapter 12 Testing Side Effects |
|
|
185 | (12) |
|
Third-Party Dependencies Are the Same As All Dependencies |
|
|
188 | (1) |
|
The Benefit of Abstracting Third-Party Dependencies |
|
|
189 | (1) |
|
Build Wrappers for Third-Party Dependencies |
|
|
189 | (2) |
|
|
191 | (3) |
|
The Downside of Using Spies |
|
|
194 | (1) |
|
|
195 | (1) |
|
|
195 | (2) |
|
Chapter 13 Testing a Conditional View Presentation |
|
|
197 | (22) |
|
Informing the User of the Checkout Completion |
|
|
198 | (5) |
|
How to Test Asynchronous Code When There Is No Callback |
|
|
203 | (5) |
|
|
208 | (2) |
|
Testing the Alert Dismiss Behavior |
|
|
210 | (6) |
|
|
216 | (3) |
|
Chapter 14 Fixing Bugs and Changing Existing Code with TDD |
|
|
219 | (6) |
|
Fixing Bugs Driven by Tests |
|
|
219 | (3) |
|
Changing Existing Code Driven by Tests |
|
|
222 | (2) |
|
|
224 | (1) |
|
Chapter 15 Keeping Tests Isolated with Fakes and Clear with Dummies |
|
|
225 | (10) |
|
Fake: How to Bypass Slow or Stateful Dependencies |
|
|
226 | (4) |
|
Dummy: How to Provide Dependencies That Are Required but Irrelevant for the Behavior Being Tested |
|
|
230 | (3) |
|
|
233 | (2) |
|
|
235 | (8) |
|
|
236 | (1) |
|
|
237 | (1) |
|
|
238 | (1) |
|
TDD and Product Development |
|
|
239 | (2) |
|
|
241 | (2) |
|
|
243 | (8) |
|
|
243 | (1) |
|
How to Test Asynchronous Code |
|
|
244 | (1) |
|
How to Test Asynchronous Code When There Is No Callback |
|
|
244 | (1) |
|
How to Test Combine Publishers |
|
|
245 | (2) |
|
How to Test Changes to SwiftUI Published Properties |
|
|
247 | (1) |
|
|
248 | (1) |
|
|
248 | (1) |
|
|
249 | (1) |
|
|
249 | (1) |
|
|
250 | (1) |
|
Appendix A Where to Go from Here |
|
|
251 | (8) |
|
|
251 | (1) |
|
|
252 | (1) |
|
|
253 | (1) |
|
|
254 | (1) |
|
Use Modularization to Tame Long Build Times |
|
|
255 | (1) |
|
How to Convince Your Team to Adopt TDD |
|
|
256 | (3) |
|
Appendix B Testing with Quick and Nimble |
|
|
259 | (8) |
|
|
260 | (2) |
|
|
262 | (5) |
|
Appendix C TDD with UIKit |
|
|
267 | (16) |
|
How to Unit Test a UIViewController |
|
|
268 | (5) |
|
|
273 | (3) |
|
How to Test ViewController Navigation and Presentation |
|
|
276 | (5) |
|
What About AppKit and WatchKit? |
|
|
281 | (2) |
Index |
|
283 | |