From 1e8c3457e1cde101fd97662230a3aab53e8e8e20 Mon Sep 17 00:00:00 2001 From: Scott Wierschem Date: Thu, 12 Sep 2024 15:56:29 -0500 Subject: [PATCH] . td Start description of Savers --- .../LoadersAndSaversExamplesTest.java | 44 +++++++ .../docs/how_to/LoadersAndSavers.md | 123 ++++++++---------- 2 files changed, 100 insertions(+), 67 deletions(-) diff --git a/approvaltests-util-tests/src/test/java/com/spun/util/persistence/LoadersAndSaversExamplesTest.java b/approvaltests-util-tests/src/test/java/com/spun/util/persistence/LoadersAndSaversExamplesTest.java index a9babf33..22145163 100644 --- a/approvaltests-util-tests/src/test/java/com/spun/util/persistence/LoadersAndSaversExamplesTest.java +++ b/approvaltests-util-tests/src/test/java/com/spun/util/persistence/LoadersAndSaversExamplesTest.java @@ -1,5 +1,6 @@ package com.spun.util.persistence; +import com.spun.util.Tuple; import org.approvaltests.Approvals; import org.junit.jupiter.api.Test; @@ -144,6 +145,48 @@ private DataBase initializeDatabase() return null; } } + + class Step4 { + // begin-snippet: step4 + public void sendOutSeniorDiscounts(DataBase database, MailServer mailServer) + { + Loader> seniorCustomerLoader = database::getSeniorCustomers; + sendOutSeniorDiscounts(mailServer, seniorCustomerLoader); + } + + public void sendOutSeniorDiscounts(MailServer mailServer, Loader> seniorCustomerLoader) + { + List seniorCustomers = seniorCustomerLoader.load(); + for (Customer customer : seniorCustomers) + { + Discount seniorDiscount = getSeniorDiscount(); + String message = generateDiscountMessage(customer, seniorDiscount); + mailServer.sendMessage(customer, message); + } + } + // end-snippet + } + class Step4_b { + // begin-snippet: step4_b + public void sendOutSeniorDiscounts(DataBase database, MailServer mailServer) + { + Loader> seniorCustomerLoader = database::getSeniorCustomers; + Saver> mailSaver = Saver2.create(mailServer::sendMessage); + sendOutSeniorDiscounts(mailSaver, seniorCustomerLoader); + } + + public void sendOutSeniorDiscounts(Saver> mailSaver, Loader> seniorCustomerLoader) + { + List seniorCustomers = seniorCustomerLoader.load(); + for (Customer customer : seniorCustomers) + { + Discount seniorDiscount = getSeniorDiscount(); + String message = generateDiscountMessage(customer, seniorDiscount); + mailSaver.save(new Tuple(customer, message)); + } + } + // end-snippet + } private String generateDiscountMessage(Customer customer, Discount seniorDiscount) { return null; @@ -185,4 +228,5 @@ public String toString() private class Discount { } + } diff --git a/approvaltests-util/docs/how_to/LoadersAndSavers.md b/approvaltests-util/docs/how_to/LoadersAndSavers.md index e9e2acdb..ab0a8960 100644 --- a/approvaltests-util/docs/how_to/LoadersAndSavers.md +++ b/approvaltests-util/docs/how_to/LoadersAndSavers.md @@ -170,7 +170,7 @@ Step 5: Now we introduce the new loader function as a parameter to the original Step 6: Update the unit tests to use the new Loader parameter. We have now removed the reliance on the database to retrieve the data. -We still rely on a mail server to send the results. +Note that we still rely on a mail server to send the results. @@ -197,72 +197,61 @@ We still rely on a mail server to send the results. } - -Step 7: Now we can remove the DataBase as a parameter altogether. - -public void sendOutSeniorDiscounts(DataBase database, MailServer mailServer, Loader<List seniorCustomerLoader) { - -  List seniorCustomers = seniorCustomerLoader.load(); - -  // ... - -} - -becomes - -public void sendOutSeniorDiscounts(MailServer, Loader<List seniorCustomerLoader) { ... } - -and we can now remove that parameter from any function that calls this one - including our test. +And we can now remove that parameter from any function that calls this one - including our test. This removes the dependency on the database for testing purposes. Why not just use a mock object to do this? -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. +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 much more overhead and initialization. But we still have a dependency on the MailServer in the example above. Thanks for pointing that out! We'll now show how to solve that problem using a Saver. -Savers +## Savers Let's continue with the above example: - -public void sendOutSeniorDiscounts(MailServer mailServer, Loader<List seniorCustomerLoader) { - -  List seniorCustomers = seniorCustomerLoader.load(); - -  for (Customer customer : seniorCustomers) { - -  Discount seniorDiscount = getSeniorDiscount(); - -  String message = generateDiscountMessage(customer, seniorDiscount); - -  mailServer.sendMessage(customer, message); - -  } - + +```java +public void sendOutSeniorDiscounts(DataBase database, MailServer mailServer) +{ + Loader> seniorCustomerLoader = database::getSeniorCustomers; + sendOutSeniorDiscounts(mailServer, seniorCustomerLoader); } +public void sendOutSeniorDiscounts(MailServer mailServer, Loader> seniorCustomerLoader) +{ + List seniorCustomers = seniorCustomerLoader.load(); + for (Customer customer : seniorCustomers) + { + Discount seniorDiscount = getSeniorDiscount(); + String message = generateDiscountMessage(customer, seniorDiscount); + mailServer.sendMessage(customer, message); + } +} +``` 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. Step 1: Determine the function that we call to save (or in this case, send) the data. public void sendOutSeniorDiscounts(MailServer mailServer, Loader<List seniorCustomerLoader) { -  List seniorCustomers = seniorCustomerLoader.load(); + List seniorCustomers = seniorCustomerLoader.load(); -  for (Customer customer : seniorCustomers) { + for (Customer customer : seniorCustomers) { -  Discount seniorDiscount = getSeniorDiscount(); + Discount seniorDiscount = getSeniorDiscount(); -  String message = generateDiscountMessage(customer, seniorDiscount); + String message = generateDiscountMessage(customer, seniorDiscount); -  **mailServer.sendMessage(new Email(customer, message));** + **mailServer.sendMessage(new Email(customer, message));** **mailSaver.save(new Email(customer, message));** -  } + } Record Email(Customer customer, String message) {} @@ -274,11 +263,11 @@ public void senior_customer_message_indicates_benefits_for_those_over_age_65() { Stack<Email> sent = new Stack<>(); -  List seniorCustomers = List.of(new Customer("Bob", "Jones", /\* ... /), / ... \*/); + List seniorCustomers = List.of(new Customer("Bob", "Jones", /\* ... /), / ... \*/); -  sendOutSeniorDiscounts(null, m -> sent.push(m), () -> seniorCustomers)); + sendOutSeniorDiscounts(null, m -> sent.push(m), () -> seniorCustomers)); -  Approvals.verifyAll(“Email”, sent); + Approvals.verifyAll(“Email”, sent); } @@ -286,27 +275,27 @@ Step 3: In the test, replace the object that does the saving with a Saver. public void senior_customer_message_indicates_benefits_for_those_over_age_65() { -  TestMailServer mailServer = new TestMailServer(); + TestMailServer mailServer = new TestMailServer(); -  List seniorCustomers = List.of(new Customer("Bob", "Jones", /\* ... /), / ... \*/); + List seniorCustomers = List.of(new Customer("Bob", "Jones", /\* ... /), / ... \*/); -  sendOutSeniorDiscounts(null, () -> mailServer, () -> seniorCustomers)); + sendOutSeniorDiscounts(null, () -> mailServer, () -> seniorCustomers)); -  Approvals.verifyAll(mailServer.getMessage()); + Approvals.verifyAll(mailServer.getMessage()); } Class TestMailServer() { -  private String message; + private String message; -  void sendMessage(Customer customer, String message) { + void sendMessage(Customer customer, String message) { -  this.message = message; + this.message = message; -  } + } -  String getMessage() { return message; } + String getMessage() { return message; } } @@ -324,11 +313,11 @@ Step 5: Now we introduce the new saver function as a parameter to the original f public void sendOutSeniorDiscounts(MailServer mailServer, Loader<List> seniorCustomerLoader) { -  // ... + // ... -  ((Saver<MailServer>)() -> mailServer.sendMessage(customer, message)).save(); + ((Saver<MailServer>)() -> mailServer.sendMessage(customer, message)).save(); -  // ... + // ... } @@ -336,11 +325,11 @@ becomes public void sendOutSeniorDiscounts(MailServer mailServer, Saver<MailServer> mailServerSaver, Loader<List> seniorCustomerLoader) { -  // ... + // ... -  mailServerSaver.save(); + mailServerSaver.save(); -  // ... + // ... } @@ -348,13 +337,13 @@ Step 6: Update the calls to this function to use the new Saver parameter. public void senior_customer_list_includes_only_those_over_age_65() { -  TestMailServer mailServer = new TestMailServer(); + TestMailServer mailServer = new TestMailServer(); -  List seniorCustomers = List.of(new Customer("Bob", "Jones", /\* ... /), / ... \*/); + List seniorCustomers = List.of(new Customer("Bob", "Jones", /\* ... /), / ... \*/); -  sendOutSeniorDiscounts(null, () -> mailServer, () -> seniorCustomers)); + sendOutSeniorDiscounts(null, () -> mailServer, () -> seniorCustomers)); -  Approvals.verifyAll(mailServer.getRecipients()); + Approvals.verifyAll(mailServer.getRecipients()); } @@ -362,11 +351,11 @@ Step 7: Now we can remove the MailServer as a parameter altogether. public void sendOutSeniorDiscounts(MailServer mailServer, Saver<MailServer> mailServerSaver, Loader<List> seniorCustomerLoader) { -  // ... + // ... -  mailServerSaver.save(); + mailServerSaver.save(); -  // ... + // ... } @@ -378,6 +367,6 @@ and we can now remove that parameter from any function that calls this one - inc This removes the dependency on the MailServer for testing purposes. -  -  + +