Skip to content

Commit 1e8c345

Browse files
committed
. td Start description of Savers
1 parent e8c6abe commit 1e8c345

File tree

2 files changed

+100
-67
lines changed

2 files changed

+100
-67
lines changed

approvaltests-util-tests/src/test/java/com/spun/util/persistence/LoadersAndSaversExamplesTest.java

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package com.spun.util.persistence;
22

3+
import com.spun.util.Tuple;
34
import org.approvaltests.Approvals;
45
import org.junit.jupiter.api.Test;
56

@@ -144,6 +145,48 @@ private DataBase initializeDatabase()
144145
return null;
145146
}
146147
}
148+
149+
class Step4 {
150+
// begin-snippet: step4
151+
public void sendOutSeniorDiscounts(DataBase database, MailServer mailServer)
152+
{
153+
Loader<List<Customer>> seniorCustomerLoader = database::getSeniorCustomers;
154+
sendOutSeniorDiscounts(mailServer, seniorCustomerLoader);
155+
}
156+
157+
public void sendOutSeniorDiscounts(MailServer mailServer, Loader<List<Customer>> seniorCustomerLoader)
158+
{
159+
List<Customer> seniorCustomers = seniorCustomerLoader.load();
160+
for (Customer customer : seniorCustomers)
161+
{
162+
Discount seniorDiscount = getSeniorDiscount();
163+
String message = generateDiscountMessage(customer, seniorDiscount);
164+
mailServer.sendMessage(customer, message);
165+
}
166+
}
167+
// end-snippet
168+
}
169+
class Step4_b {
170+
// begin-snippet: step4_b
171+
public void sendOutSeniorDiscounts(DataBase database, MailServer mailServer)
172+
{
173+
Loader<List<Customer>> seniorCustomerLoader = database::getSeniorCustomers;
174+
Saver<Tuple<Customer, String>> mailSaver = Saver2.create(mailServer::sendMessage);
175+
sendOutSeniorDiscounts(mailSaver, seniorCustomerLoader);
176+
}
177+
178+
public void sendOutSeniorDiscounts(Saver<Tuple<Customer, String>> mailSaver, Loader<List<Customer>> seniorCustomerLoader)
179+
{
180+
List<Customer> seniorCustomers = seniorCustomerLoader.load();
181+
for (Customer customer : seniorCustomers)
182+
{
183+
Discount seniorDiscount = getSeniorDiscount();
184+
String message = generateDiscountMessage(customer, seniorDiscount);
185+
mailSaver.save(new Tuple(customer, message));
186+
}
187+
}
188+
// end-snippet
189+
}
147190
private String generateDiscountMessage(Customer customer, Discount seniorDiscount)
148191
{
149192
return null;
@@ -185,4 +228,5 @@ public String toString()
185228
private class Discount
186229
{
187230
}
231+
188232
}

approvaltests-util/docs/how_to/LoadersAndSavers.md

Lines changed: 56 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ Step 5: Now we introduce the new loader function as a parameter to the original
170170

171171
Step 6: Update the unit tests to use the new Loader parameter.
172172
We have now removed the reliance on the database to retrieve the data.
173-
We still rely on a mail server to send the results.
173+
Note that we still rely on a mail server to send the results.
174174

175175
<!-- Snippet Compare: step0, step0_b -->
176176

@@ -197,72 +197,61 @@ We still rely on a mail server to send the results.
197197
}
198198
</pre>
199199

200-
201-
Step 7: Now we can remove the DataBase as a parameter altogether.
202-
203-
public void sendOutSeniorDiscounts(DataBase database, MailServer mailServer, Loader&lt;List<Customer&gt;> seniorCustomerLoader) {
204-
205-
&nbsp; List seniorCustomers = seniorCustomerLoader.load();
206-
207-
&nbsp; // ...
208-
209-
}
210-
211-
becomes
212-
213-
public void sendOutSeniorDiscounts(MailServer, Loader&lt;List<Customer&gt;> seniorCustomerLoader) { ... }
214-
215-
and we can now remove that parameter from any function that calls this one - including our test.
200+
And we can now remove that parameter from any function that calls this one - including our test.
216201

217202
This removes the dependency on the database for testing purposes.
218203

219204
Why not just use a mock object to do this?
220205

221-
Because mocking the object in question may require much more than what we are doing here. In this case we are simply replacing a call to a method with the result of that method - as if it were called. Defining a mock object would require more overhead and initialization.
206+
Because mocking the object in question may require much more than what we are doing here.
207+
In this case we are simply replacing a call to a method with the result of that method - as if it were called.
208+
Defining a mock object would require much more overhead and initialization.
222209

223210
But we still have a dependency on the MailServer in the example above.
224211

225212
Thanks for pointing that out! We'll now show how to solve that problem using a Saver.
226213

227-
Savers
214+
## Savers
228215

229216
Let's continue with the above example:
230-
231-
public void sendOutSeniorDiscounts(MailServer mailServer, Loader&lt;List<Customer&gt;> seniorCustomerLoader) {
232-
233-
&nbsp; List seniorCustomers = seniorCustomerLoader.load();
234-
235-
&nbsp; for (Customer customer : seniorCustomers) {
236-
237-
&nbsp; Discount seniorDiscount = getSeniorDiscount();
238-
239-
&nbsp; String message = generateDiscountMessage(customer, seniorDiscount);
240-
241-
&nbsp; mailServer.sendMessage(customer, message);
242-
243-
&nbsp; }
244-
217+
<!-- Snippet: step4 -->
218+
```java
219+
public void sendOutSeniorDiscounts(DataBase database, MailServer mailServer)
220+
{
221+
Loader<List<Customer>> seniorCustomerLoader = database::getSeniorCustomers;
222+
sendOutSeniorDiscounts(mailServer, seniorCustomerLoader);
245223
}
246224

225+
public void sendOutSeniorDiscounts(MailServer mailServer, Loader<List<Customer>> seniorCustomerLoader)
226+
{
227+
List<Customer> seniorCustomers = seniorCustomerLoader.load();
228+
for (Customer customer : seniorCustomers)
229+
{
230+
Discount seniorDiscount = getSeniorDiscount();
231+
String message = generateDiscountMessage(customer, seniorDiscount);
232+
mailServer.sendMessage(customer, message);
233+
}
234+
}
235+
```
247236
Here we're sending out an email message. But we don't really care if it gets sent, we just want to make sure it contains the information we expect. Replacing the MailServer object with a Saver is very similar to the process of introducing a Loader.
248237

249238
Step 1: Determine the function that we call to save (or in this case, send) the data.
250239

251240
public void sendOutSeniorDiscounts(MailServer mailServer, Loader&lt;List<Customer&gt;> seniorCustomerLoader) {
252241

253-
&nbsp; List seniorCustomers = seniorCustomerLoader.load();
242+
List seniorCustomers = seniorCustomerLoader.load();
254243

255-
&nbsp; for (Customer customer : seniorCustomers) {
244+
for (Customer customer : seniorCustomers) {
256245

257-
&nbsp; Discount seniorDiscount = getSeniorDiscount();
246+
Discount seniorDiscount = getSeniorDiscount();
258247

259-
&nbsp; String message = generateDiscountMessage(customer, seniorDiscount);
248+
String message = generateDiscountMessage(customer, seniorDiscount);
260249

261-
&nbsp; **mailServer.sendMessage(new Email(customer, message));**
250+
**mailServer.sendMessage(new Email(customer, message));**
262251

263252
**mailSaver.save(new Email(customer, message));**
264253

265-
&nbsp; }
254+
}
266255

267256
Record Email(Customer customer, String message) {}
268257

@@ -274,39 +263,39 @@ public void senior_customer_message_indicates_benefits_for_those_over_age_65() {
274263

275264
Stack&lt;Email&gt; sent = new Stack<>();
276265

277-
&nbsp; List seniorCustomers = List.of(new Customer("Bob", "Jones", /\* ... /), / ... \*/);
266+
List seniorCustomers = List.of(new Customer("Bob", "Jones", /\* ... /), / ... \*/);
278267

279-
&nbsp; sendOutSeniorDiscounts(null, m -> sent.push(m), () -> seniorCustomers));
268+
sendOutSeniorDiscounts(null, m -> sent.push(m), () -> seniorCustomers));
280269

281-
&nbsp; Approvals.verifyAll(“Email”, sent);
270+
Approvals.verifyAll(“Email”, sent);
282271

283272
}
284273

285274
Step 3: In the test, replace the object that does the saving with a Saver.
286275

287276
public void senior_customer_message_indicates_benefits_for_those_over_age_65() {
288277

289-
&nbsp; TestMailServer mailServer = new TestMailServer();
278+
TestMailServer mailServer = new TestMailServer();
290279

291-
&nbsp; List seniorCustomers = List.of(new Customer("Bob", "Jones", /\* ... /), / ... \*/);
280+
List seniorCustomers = List.of(new Customer("Bob", "Jones", /\* ... /), / ... \*/);
292281

293-
&nbsp; sendOutSeniorDiscounts(null, () -> mailServer, () -> seniorCustomers));
282+
sendOutSeniorDiscounts(null, () -> mailServer, () -> seniorCustomers));
294283

295-
&nbsp; Approvals.verifyAll(mailServer.getMessage());
284+
Approvals.verifyAll(mailServer.getMessage());
296285

297286
}
298287

299288
Class TestMailServer() {
300289

301-
&nbsp; private String message;
290+
private String message;
302291

303-
&nbsp; void sendMessage(Customer customer, String message) {
292+
void sendMessage(Customer customer, String message) {
304293

305-
&nbsp; this.message = message;
294+
this.message = message;
306295

307-
&nbsp; }
296+
}
308297

309-
&nbsp; String getMessage() { return message; }
298+
String getMessage() { return message; }
310299

311300
}
312301

@@ -324,49 +313,49 @@ Step 5: Now we introduce the new saver function as a parameter to the original f
324313

325314
public void sendOutSeniorDiscounts(MailServer mailServer, Loader&lt;List&gt; seniorCustomerLoader) {
326315

327-
&nbsp; // ...
316+
// ...
328317

329-
&nbsp; ((Saver&lt;MailServer&gt;)() -> mailServer.sendMessage(customer, message)).save();
318+
((Saver&lt;MailServer&gt;)() -> mailServer.sendMessage(customer, message)).save();
330319

331-
&nbsp; // ...
320+
// ...
332321

333322
}
334323

335324
becomes
336325

337326
public void sendOutSeniorDiscounts(MailServer mailServer, Saver&lt;MailServer&gt; mailServerSaver, Loader&lt;List&gt; seniorCustomerLoader) {
338327

339-
&nbsp; // ...
328+
// ...
340329

341-
&nbsp; mailServerSaver.save();
330+
mailServerSaver.save();
342331

343-
&nbsp; // ...
332+
// ...
344333

345334
}
346335

347336
Step 6: Update the calls to this function to use the new Saver parameter.
348337

349338
public void senior_customer_list_includes_only_those_over_age_65() {
350339

351-
&nbsp; TestMailServer mailServer = new TestMailServer();
340+
TestMailServer mailServer = new TestMailServer();
352341

353-
&nbsp; List seniorCustomers = List.of(new Customer("Bob", "Jones", /\* ... /), / ... \*/);
342+
List seniorCustomers = List.of(new Customer("Bob", "Jones", /\* ... /), / ... \*/);
354343

355-
&nbsp; sendOutSeniorDiscounts(null, () -> mailServer, () -> seniorCustomers));
344+
sendOutSeniorDiscounts(null, () -> mailServer, () -> seniorCustomers));
356345

357-
&nbsp; Approvals.verifyAll(mailServer.getRecipients());
346+
Approvals.verifyAll(mailServer.getRecipients());
358347

359348
}
360349

361350
Step 7: Now we can remove the MailServer as a parameter altogether.
362351

363352
public void sendOutSeniorDiscounts(MailServer mailServer, Saver&lt;MailServer&gt; mailServerSaver, Loader&lt;List&gt; seniorCustomerLoader) {
364353

365-
&nbsp; // ...
354+
// ...
366355

367-
&nbsp; mailServerSaver.save();
356+
mailServerSaver.save();
368357

369-
&nbsp; // ...
358+
// ...
370359

371360
}
372361

@@ -378,6 +367,6 @@ and we can now remove that parameter from any function that calls this one - inc
378367

379368
This removes the dependency on the MailServer for testing purposes.
380369

381-
&nbsp;
382370

383-
&nbsp;
371+
372+

0 commit comments

Comments
 (0)