Upgrade to Pro — share decks privately, control downloads, hide ads and more …

JUnitで闘うレガシーコード改善

Fb8ec8fe6cb5371445b58d7fc8aa18b4?s=47 YutaSaito
June 19, 2022
350

 JUnitで闘うレガシーコード改善

Fb8ec8fe6cb5371445b58d7fc8aa18b4?s=128

YutaSaito

June 19, 2022
Tweet

Transcript

  1. JUnitͰಆ͏ϨΨγʔίʔυվળ ++6($$$4QSJOH ᜊ౻༔ଠ!:VUB4BJUP

  2. ࣗݾ঺հ w ᜊ౻༔ଠ w αʔόαΠυΤϯδχΞ؀ڥ੔උͱ͔΍ͬͯΔ w ϨΨγʔίʔυͱಆ͖ͬͯ·ͨ͠ɻ ݱࡏ΋  w

    5XJUUFS!:VUB4BJUP
  3. ηογϣϯ಺༰ w ಺༰ w +6OJUΛར༻ͯ͠ϨΨγʔίʔυΛվળ͢ΔͨΊʹࢲ͕औΓ૊Μ Ͱ͍Δ͜ͱΛ͝঺հ͠·͢ɻ w ໨ඪ w ೔ʑͷۀ຿ͰϨΨγʔίʔυʹۤ࿑͍ͯ͠Δਓʹɺ+6OJUΛར༻

    ͨ͠ϦϑΝΫλϦϯάΛ஌ͬͯ΋Β͏ w ٕज़ෛ࠴Λ૿΍͞ͳ͍ͨΊʹςετίʔυΛνʔϜͷจԽʹऔΓ ೖΕ͍ͨͱࢥͬͯ΋Β͏
  4. ϨΨγʔίʔυͷྫ ࢲ͸͍͔ͭ͘ͷγεςϜͰҎԼͷΑ͏ͳίʔυΛݟΔ͜ͱ͕ ͋Γ·ͨ͠ɻ /** * ൢചརӹܭࢉ * * @param price

    ঎඼୅ۚ * @param shippingSize ঎඼αΠζ * @return ച্ */ public Sales profitCalculate(int price, ShippingSize shippingSize) { if (price < 1_000) { throw new IllegalArgumentException("priceʹ͸1,000ԁҎ্Λઃఆ͍ͯͩ͘͠͞ɻ"); } Sales sales = new Sales(); sales.price = price; sales.profit = price; // ख਺ྉܭࢉ feeCalculate(sales); // ഑ૹྉܭࢉ deliveryFeeCalculate(sales, shippingSize); return sales; }
  5. ϨΨγʔίʔυͷྫ ࢲ͸͍͔ͭ͘ͷγεςϜͰҎԼͷΑ͏ͳίʔυΛݟΔ͜ͱ͕ ͋Γ·ͨ͠ɻ /** * ൢചརӹܭࢉ * * @param price

    ঎඼୅ۚ * @param shippingSize ঎඼αΠζ * @return ച্ */ public Sales profitCalculate(int price, ShippingSize shippingSize) { if (price < 1_000) { throw new IllegalArgumentException("priceʹ͸1,000ԁҎ্Λઃఆ͍ͯͩ͘͠͞ɻ"); } Sales sales = new Sales(); sales.price = price; sales.profit = price; // ख਺ྉܭࢉ feeCalculate(sales); // ഑ૹྉܭࢉ deliveryFeeCalculate(sales, shippingSize); return sales; } ϝιουʹTBMFTΛ౉ͯ͠ ͜ͷϝιουͷதͰTBMFTΛߋ৽͍ͯ͠Δ
  6. ϨΨγʔίʔυʹ৽͍͠ػೳΛ௥Ճ͢Δ Ͱ͸͜ͷίʔυʹػೳΛ௥Ճͯ͠Έ·͢ɻ ࠓ͚ͩʮख਺ྉແྉʯΩϟϯϖʔϯΛߦ͏ͱ͠·͢ɻ /** * ൢചརӹܭࢉ * * @param price

    ঎඼୅ۚ * @param shippingSize ঎඼αΠζ * @return ച্ */ public Sales profitCalculate(int price, ShippingSize shippingSize) { if (price < 1_000) { throw new IllegalArgumentException("priceʹ͸1,000ԁҎ্Λઃఆ͍ͯͩ͘͠͞ɻ"); } Sales sales = new Sales(); sales.price = price; sales.profit = price; // ख਺ྉܭࢉ feeCalculate(sales); // ഑ૹྉܭࢉ deliveryFeeCalculate(sales, shippingSize); return sales; }
  7. ৽͍͠ػೳΛ௥Ճ͢Δ ख਺ྉΛແྉʹ͢Δ͸͜͜Λ௚ͤ͹ྑ͍ͬΆ͍ /** * ൢചརӹܭࢉ * * @param price ঎඼୅ۚ

    * @param shippingSize ঎඼αΠζ * @return ച্ */ public Sales profitCalculate(int price, ShippingSize shippingSize) { if (price < 1_000) { throw new IllegalArgumentException("priceʹ͸1,000ԁҎ্Λઃఆ͍ͯͩ͘͠͞ɻ"); } Sales sales = new Sales(); sales.price = price; sales.profit = price; // ख਺ྉܭࢉ feeCalculate(sales); // ഑ૹྉܭࢉ deliveryFeeCalculate(sales, shippingSize); return sales; }
  8. ৽͍͠ػೳΛ௥Ճ͢Δ ख਺ྉܭࢉΛແྉʹ͢Δίʔυʹมߋ private void feeCalculate(Sales sales) { int rate; if

    (sales.price < 5_000) { rate = 20; } else if (sales.price < 10_000) { rate = 10; } else { rate = 5; } int fee = sales.price * rate / 100; sales.fee = fee; sales.profit = sales.profit - fee; } private void feeCalculate(Sales sales) { sales.fee = 0; } ݩͷίʔυ मਖ਼ޙͷίʔυ
  9. ৽͍͠ػೳΛ௥Ճ͢Δ ػೳվमͰ͖ͨʂ0,ʂ

  10. ৽͍͠ػೳΛ௥Ճ͢Δ ػೳվमͰ͖ͨʂ0,ʂ Μʁ ൢചརӹ͕૝ఆΑΓଟ͍ʁ

  11. όάͷݪҼΛ֬ೝ͢Δ શ෦ͷίʔυΛݟͯΈ·͢ private void feeCalculate(Sales sales) { sales.fee = 0;

    } private void deliveryFeeCalculate(Sales sales, ShippingSize shippingSize) { int deliveryFee = switch (shippingSize) { case SMALL -> 100; case MEDIUM -> 200; case LARGE -> 300; }; // ഑ૹྉ͕300ԁҎ্ͳΒख਺ྉ͔Β100ԁׂҾ if (deliveryFee >= 300) { sales.fee -= 100; sales.profit += 100; } sales.deliveryFee = deliveryFee; sales.profit = sales.profit - deliveryFee; } // ख਺ྉܭࢉ feeCalculate(sales); // ഑ૹྉܭࢉ deliveryFeeCalculate(sales, shippingSize); return sales;
  12. όάͷݪҼΛ֬ೝ͢Δ શ෦ͷίʔυΛݟͯΈ·͢ private void feeCalculate(Sales sales) { sales.fee = 0;

    } private void deliveryFeeCalculate(Sales sales, ShippingSize shippingSize) { int deliveryFee = switch (shippingSize) { case SMALL -> 100; case MEDIUM -> 200; case LARGE -> 300; }; // ഑ૹྉ͕300ԁҎ্ͳΒख਺ྉ͔Β100ԁׂҾ if (deliveryFee >= 300) { sales.fee -= 100; sales.profit += 100; } sales.deliveryFee = deliveryFee; sales.profit = sales.profit - deliveryFee; } // ख਺ྉܭࢉ feeCalculate(sales); // ഑ૹྉܭࢉ deliveryFeeCalculate(sales, shippingSize); return sales; ख਺ྉ͕ϚΠφεʹͳΔ
  13. ϨΨγʔίʔυͱ͸ ࠓճͷίʔυʹ͸ҎԼͷΑ͏ͳ໰୊͕͋Γ·ͨ͠ɻ ɾίʔυΛमਖ਼͢ΔͱଞͷՕॴʹ·ͰӨڹͯ͠͠·͏ ɾίʔυͷཧղʹ͕͔͔࣌ؒΔ Մಡੑ͕௿͍  ࢲ͕ؔΘ͖ͬͯͨγεςϜͰ͸ɺ͜ͷΑ͏ͳίʔυ͕௕͍ظ ؒଘࡏ͠ɺվળ͞Εͣʹܧଓͯ͠ར༻͞Ε͍ͯ·ͨ͠ɻ ͜ͷΑ͏ͳঢ়ଶΛϨΨγʔίʔυͱࠓճ͸ݺͼ·͢ɻ

  14. ͦ͏ͩϦϑΝΫλϦϯά͠Α͏ʂ

  15. ͲͷΑ͏ʹमਖ਼͢Δʁ ෭࡞༻Λͳͯ͘͠ݺͼग़͠ݩϝιου ౰ϝιου ͰΫϥεͷ஋Λઃఆ͞ ͍ͤͨͰ͢ɻҎԼ͸मਖ਼ޙͷΠϝʔδ /** * ൢചརӹܭࢉ * *

    @param price ঎඼୅ۚ * @param shippingSize ঎඼αΠζ * @return ച্ */ public Sales profitCalculate(int price, ShippingSize shippingSize) { if (price < 1_000) { throw new IllegalArgumentException("priceʹ͸1,000ԁҎ্Λઃఆ͍ͯͩ͘͠͞ɻ"); } Sales sales = new Sales(); sales.price = price; // ख਺ྉܭࢉ int fee = feeCalculate(sales.price); // ഑ૹྉܭࢉ int deliveryFee = deliveryFeeCalculate(shippingSize); // ഑ૹྉ͕300ԁҎ্ͳΒख਺ྉ͔Β100ԁׂҾ if (deliveryFee >= 300) { fee = max(fee - 100, 100); } sales.fee = fee; sales.deliveryFee = deliveryFee; sales.profit = price - fee - deliveryFee; return sales; }
  16. खಈͰͷςετ͸೉͍͠৔߹΋͋Δ ࠓճͷΑ͏ͳίʔυΛϦϑΝΫλϦϯάͯ͠΋ɺ σʔλͷ४උ͕େมɺܦ࿏͕ෳࡶͳͲͷཧ༝ͰखಈͰςετ ͢Δͷ΋೉͍͠৔߹΋͋Γɺόά͕ൃੜ͢ΔՄೳੑ͕͋Γ· ͢ɻ

  17. खಈͰͷςετ͸೉͍͠৔߹΋͋Δ ࠓճͷΑ͏ͳίʔυΛϦϑΝΫλϦϯάͯ͠΋ɺ σʔλͷ४උ͕େมɺܦ࿏͕ෳࡶͳͲͷཧ༝ͰखಈͰςετ ͢Δͷ΋೉͍͠৔߹΋͋Γɺόά͕ൃੜ͢ΔՄೳੑ͕͋Γ· ͢ɻ +6OJUͰςετίʔυΛॻ͚͹ ҆શʹϦϑΝΫλϦϯάͰ͖·͢

  18. ςετίʔυͷ࡞੒ ϦϑΝΫλϦϯάΛߦ͏લʹɺςετίʔυΛ࡞੒͠શͯ QBTT͢Δ͜ͱΛ֬ೝ͠·͢ɻ @Test void ഑ૹྉ͕300ԁ() { Sales actual =

    new SalesService().profitCalculate(1_000, ShippingSize.LARGE); assertEquals(1_000, actual.price); assertEquals(100, actual.fee); assertEquals(300, actual.deliveryFee); assertEquals(600, actual.profit); }
  19. ϦϑΝΫλϦϯά͢Δ Ͱ͸ϦϑΝΫλϦϯά͠·͢ɻ /** * ൢചརӹܭࢉ * * @param price ঎඼୅ۚ

    * @param shippingSize ঎඼αΠζ * @return ച্ */ public Sales profitCalculate(int price, ShippingSize shippingSize) { if (price < 1_000) { throw new IllegalArgumentException("priceʹ͸1,000ԁҎ্Λઃఆ͍ͯͩ͘͠͞ɻ"); } Sales sales = new Sales(); sales.price = price; // ख਺ྉܭࢉ int fee = feeCalculate(sales.price); // ഑ૹྉܭࢉ int deliveryFee = deliveryFeeCalculate(shippingSize); sales.fee = fee; sales.deliveryFee = deliveryFee; sales.profit = price - fee - deliveryFee; return sales; }
  20. ςετίʔυΛ࣮ߦ ϦϑΝΫλϦϯάΛϛεΔͱςετΤϥʔ͕ൃੜ͠·͢

  21. मਖ਼͢Δ ޡ͍ͬͯͨՕॴΛमਖ਼͠·͢ɻ /** * ൢചརӹܭࢉ * * @param price ঎඼୅ۚ

    * @param shippingSize ঎඼αΠζ * @return ച্ */ public Sales profitCalculate(int price, ShippingSize shippingSize) { if (price < 1_000) { throw new IllegalArgumentException("priceʹ͸1,000ԁҎ্Λઃఆ͍ͯͩ͘͠͞ɻ"); } Sales sales = new Sales(); sales.price = price; // ख਺ྉܭࢉ int fee = feeCalculate(sales); // ഑ૹྉܭࢉ int deliveryFee = deliveryFeeCalculate(sales, shippingSize); // ഑ૹྉ͕300ԁҎ্ͳΒख਺ྉ͔Β100ԁׂҾ if (deliveryFee >= 300) { fee = max(fee - 100, 100); } sales.fee = fee; sales.deliveryFee = deliveryFee; sales.profit = price - fee - deliveryFee; return sales; } ͕͜͜࿙Ε͍ͯͨ
  22. ςετίʔυΛ࣮ߦ ςετΛ࣮ߦͯ͠શͯQBTTͨ͠ΒϦϑΝΫλϦϯά੒ޭͰ ͢ɻ

  23. ͜ΕͰϨΨγʔίʔυΛվળ͍ͯͧ͘͠ʂ

  24. ͜ΕͰϨΨγʔίʔυΛվળ͍ͯͧ͘͠ʂ ͋Εʁվળ͍ͯ͠Δ͸ͣͳͷʹ ϨΨγʔίʔυશવݮΒͳ͍͔΋ʁ

  25. ݸਓͷϦϑΝΫλϦϯάʹ͸ݶք͕͋Δ Ұਓ͕ςετΛ࡞੒ͯ͠ϦϑΝΫλϦϯάΛߦͳͬͯ΋ɺଞ ͷਓ͕৽ͨʹϨΨγʔίʔυΛ૿΍͢εϐʔυͷํ͕ૣ͍Մ ೳੑ͕͋Γ·͢ɻ ࠷ॳ͸෦԰ͷ૭ׂ͕Ε͍ͯΔ͚͕ͩͩͬͨɺ࣍ୈʹ͍͔ͭ͘ͷ෦԰ͷ૭ׂ͕Ε͍ͯΔঢ়ଶʹͳΔ ׂΕ૭ཧ࿦

  26. ςετίʔυΛॻ͘จԽΛ࡞Δ νʔϜͷଟ͘ͷਓ͕ςετίʔυΛॻ͘Α͏ʹͳΕ͹ ɾόά͕গͳ͘ͳΔ ɾϦϑΝΫλϦϯά͠΍͘͢ͳΔ ɾྑ͍ίʔυ͕૿͑Δ ϨΨγʔίʔυͷ૿Ճεϐʔυྑ͍ίʔυͷ૿Ճεϐʔυ ʹͳͬͯγεςϜ͕վળ͞Ε͍͖ͯ·͢

  27. Ͳ͏΍ͬͯςετίʔυจԽΛ࡞Δʁ ࢲ͸νʔϜʹςετίʔυΛॻ͘จԽΛ࡞ΔͨΊʹ ҎԼͷΑ͏ͳ͜ͱΛ࣮ࢪ͠·ͨ͠ɻ ɾڧ੍తʹςετίʔυΛҙࣝ͢Δ؀ڥͷ੔උ ɾςετίʔυ͕ޮՌతʹॻ͚͍ͯΔ͔ΛՄࢹԽ ɾςετίʔυ࡞੒Λָʹ͢ΔϥΠϒϥϦͷಋೖ

  28. Ͳ͏΍ͬͯςετίʔυจԽΛ࡞Δʁ ࢲ͸νʔϜʹςετίʔυΛॻ͘จԽΛ࡞ΔͨΊʹ ҎԼͷΑ͏ͳ͜ͱΛ࣮ࢪ͠·ͨ͠ɻ ɾڧ੍తʹςετίʔυΛҙࣝ͢Δ؀ڥͷ੔උ ɾςετίʔυ͕ޮՌతʹॻ͚͍ͯΔ͔ΛՄࢹԽ ɾςετίʔυ࡞੒Λָʹ͢ΔϥΠϒϥϦͷಋೖ

  29. $*ͷಋೖ σϓϩΠϑϩʔʹ$* ςετ࣮ߦ Λಋೖ͠ɺ ςετʹࣦഊͨ͠ΒΤϥʔʹͯ͠σϓϩΠͤ͞ͳ͍͜ͱͰ ڧ੍తʹςετΛҙࣝ͢Δঢ়ଶΛ࡞Γ·ͨ͠ɻ ίϛοτ Ϗϧυ ςετ σϓϩΠ

    ಛఆͷϒϥϯνʹϚʔδ͞Εͨࡍʹ ࣗಈͰςετ͢Δ
  30. $*ͷಋೖ (SBEMF΍.BWFOͰ$*Λಋೖ͢Δͷʹಛผͳઃఆ͸ඞཁͳ͠ ςετίʔυ͑͋͞Ε͹ɺCVJMEͱಉ࣌ʹςετ΋࣮ߦ͞Ε ·͢ɻ $ ./gradlew --console=plain build > Task

    :compileJava UP-TO-DATE > Task :processResources UP-TO-DATE > Task :classes UP-TO-DATE > Task :bootJarMainClassName UP-TO-DATE > Task :bootJar UP-TO-DATE > Task :jar UP-TO-DATE > Task :assemble UP-TO-DATE > Task :spotlessInternalRegisterDependencies UP-TO-DATE > Task :spotlessJava UP-TO-DATE > Task :spotlessJavaCheck UP-TO-DATE > Task :spotlessCheck UP-TO-DATE > Task :compileTestJava UP-TO-DATE > Task :processTestResources NO-SOURCE > Task :testClasses UP-TO-DATE > Task :test UP-TO-DATE > Task :check UP-TO-DATE > Task :build UP-TO-DATE BUILD SUCCESSFUL in 1s 10 actionable tasks: 10 up-to-date UFTUλεΫ͕࣮ߦ͞ΕΔ
  31. Ͳ͏΍ͬͯςετίʔυจԽΛ࡞Δʁ ࢲ͸νʔϜʹςετίʔυΛॻ͘จԽΛ࡞ΔͨΊʹ ҎԼͷΑ͏ͳ͜ͱΛ࣮ࢪ͠·ͨ͠ɻ ɾڧ੍తʹςετίʔυΛҙࣝ͢Δ؀ڥͷ੔උ ɾςετίʔυ͕ޮՌతʹॻ͚͍ͯΔ͔ΛՄࢹԽ ɾςετίʔυ࡞੒Λָʹ͢ΔϥΠϒϥϦͷಋೖ

  32. ΧόϨοδΛՄࢹԽ ΧόϨοδΛՄࢹԽ͢Δ͜ͱͰ ޮՌతʹςετίʔυ͕ॻ͚͍ͯΔ͔͕෼͔Γɺ ·ͨ਺஋ͱͯ݁͠Ռ͕ग़Δ͜ͱͰϞνϕʔγϣϯʹܨ͕Δ͔ ΋ͱߟ͍͑ͯ·͢ɻ ҎԼͰ͸+B$P$PͰग़ྗͨ͠ϨϙʔτΛද͍ࣔͯ͠·͢ɻ

  33. +B$P$Pͷಋೖ (SBEMF΍.BWFOʹ͸+B$P$Pͷ1MVHJOΛ௥Ճͯ͋͛͠Ε͹ ར༻ՄೳͰ͢ɻৄࡉ͸ϦϯΫΛ͝ཡ͍ͩ͘͞ɻ plugins { id 'jacoco' } jacocoTestReport {

    dependsOn test reports { xml.required = false csv.required = false html.required = true } } <plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> <version>0.8.9-SNAPSHOT</version> </plugin> <project> <reporting> <plugins> <plugin> <groupId>org.jacoco</groupId> <artifactId>jacoco-maven-plugin</artifactId> <reportSets> <reportSet> <reports> <report>report</report> </reports> </reportSet> </reportSets> </plugin> </plugins> </reporting> </project> CVJMEHSBEMF QPNYNM IUUQTEPDTHSBEMFPSHDVSSFOUVTFSHVJEFKBDPDP@QMVHJOIUNM IUUQTXXXKBDPDPPSHKBDPDPUSVOLEPDNBWFOIUNM
  34. Ͳ͏΍ͬͯςετίʔυจԽΛ࡞Δʁ ࢲ͸νʔϜʹςετίʔυΛॻ͘จԽΛ࡞ΔͨΊʹ ҎԼͷΑ͏ͳ͜ͱΛ࣮ࢪ͠·ͨ͠ɻ ɾڧ੍తʹςετίʔυΛҙࣝ͢Δ؀ڥͷ੔උ ɾςετίʔυ͕ޮՌతʹॻ͚͍ͯΔ͔ΛՄࢹԽ ɾςετίʔυ࡞੒Λָʹ͢ΔϥΠϒϥϦͷಋೖ

  35. ςετίʔυಋೖͷ՝୊ ɾॻ͍ͨ͜ͱ͕ͳ͍ਓͷ৺ཧతϋʔυϧ ɾϨΨγʔίʔυʹςετίʔυΛॻ͘ͷ͕େม ςετ͕૝ఆ͞ΕͨίʔυͰ͸ͳ͍ͨΊςετίʔυͷ࡞੒ʹ͕͔͔࣌ؒΔ ։ൃʹ͔͔࣌ؒΔ ΊΜͲͦ͘͞͏

  36. ςετίʔυಋೖͷ՝୊ ɾॻ͍ͨ͜ͱ͕ͳ͍ਓͷ৺ཧతϋʔυϧ ɾϨΨγʔίʔυʹςετίʔυΛॻ͘ͷ͕େม ςετ͕૝ఆ͞ΕͨίʔυͰ͸ͳ͍ͨΊςετίʔυͷ࡞੒ʹ͕͔͔࣌ؒΔ ։ൃʹ͔͔࣌ؒΔ ΊΜͲͦ͘͞͏ ָΛ͢ΔͨΊʹϥΠϒϥϦΛಋೖ͠Α͏ʂ ςετϥΠϒϥϦͷಋೖͰ͋Ε͹ɺϓϩμΫγϣϯίʔυ΁ ͷӨڹ΋ݶఆతͰൺֱతؾܰʹಋೖͰ͖·͢

  37. ϞοΫΛ࢖͏ %#ૢ࡞ɺෳࡶͳϝιουΛݺͼग़͢ͳͲςετίʔυΛॻ ͘ͷʹۤ࿑͢Δίʔυ΋ϞοΫΛར༻͢Ε͹؆୯ʹςετՄ ೳʹͳΓ·͢ɻ /** * ׂҾֹۚͷܭࢉ * * @param

    userId * @return ׂҾֹۚ */ public int discount(String userId) { LocalDate toDate = localDateService.now(); LocalDate fromDate = toDate.minusDays(7); List<Purchase> purchases = purchaseRepository.findByPurchaseDateBetween(userId, fromDate, toDate); if (purchases.size() >= 5) { return 200; } if (purchases.size() >= 3) { return 100; } return 0; }
  38. ϞοΫΛ࢖͏ ϞοΫΛར༻ͨ͠ςετ͸͜ͷΑ͏ͳܗʹͳΓ·͢ɻ .PDLJUPΛར༻ͨ͠ྫ class DiscountServiceTest { @Mock private LocalDateService localDateService;

    @Mock private PurchaseRepository purchaseRepository; @InjectMocks private DiscountService discountService; @BeforeEach void beforeEach() { MockitoAnnotations.openMocks(this); } @Test void औҾ݅਺͕5݅ͷ৔߹͸200ԁׂҾ() { String userId = "123"; LocalDate toDate = LocalDate.of(2022, 6, 13); when(localDateService.now()).thenReturn(toDate); LocalDate fromDate = LocalDate.of(2022, 6, 6); List<Purchase> purcases = IntStream.range(1, 6).mapToObj(i -> new Purchase(toDate, 100 * i)).toList(); when(purchaseRepository.findByPurchaseDateBetween(userId, fromDate, toDate)) .thenReturn(purcases); int actual = discountService.discount(userId); assertEquals(200, actual); verify(localDateService).now(); verify(purchaseRepository).findByPurchaseDateBetween(userId, fromDate, toDate); } } ϝιουͷ໭Γ஋ΛϞοΫԽ
  39. ΞαʔγϣϯϥΠϒϥϦΛ࢖͏ +6OJUʹσϑΥϧτͰ༻ҙ͞Ε͍ͯΔΞαʔγϣϯͩͱςε τίʔυͷ࡞੒͕ෳࡶʹͳΔ͜ͱ͕͋Γ·͢ɻ List<Person> actual = personService.ranking(); List<Person> taroFilterdActual =

    actual.stream() .filter(person -> person.getName().equals("taro") && person.getAge() == 20) .toList(); assertEquals(1, taroFilterdActual.size()); List<Person> hanakoFilterdActual = actual.stream() .filter(person -> person.getName().equals("hanako") && person.getAge() == 25) .toList(); assertEquals(1, hanakoFilterdActual.size()); 1FSTPOΫϥε͸ FRVBMTϝιουΛ༻ҙ͍ͯ͠ͳ͍
  40. ΞαʔγϣϯϥΠϒϥϦΛ࢖͏ +6OJUʹσϑΥϧτͰ༻ҙ͞Ε͍ͯΔΞαʔγϣϯͩͱςε τίʔυͷ࡞੒͕ෳࡶʹͳΔ͜ͱ͕͋Γ·͢ɻ List<Person> actual = personService.ranking(); List<Person> taroFilterdActual =

    actual.stream() .filter(person -> person.getName().equals("taro") && person.getAge() == 20) .toList(); assertEquals(1, taroFilterdActual.size()); List<Person> hanakoFilterdActual = actual.stream() .filter(person -> person.getName().equals("hanako") && person.getAge() == 25) .toList(); assertEquals(1, hanakoFilterdActual.size()); List<Person> actual = personService.ranking(); Person taro = new Person(0L, "taro", 20); Person hanako = new Person(0L, "hanako", 25); assertThat(actual) .usingRecursiveFieldByFieldElementComparatorOnFields("name", "age") .contains(taro, hanako); ΞαʔγϣϯϥΠϒϥϦΛར༻͢Δ͜ͱͰ؆୯ʹॻ͚ΔՄೳੑ͕͋Γ·͢ɻ ҎԼ͸"TTFSU+Λར༻ͨ͠ྫͰ͢ɻ 1FSTPOΫϥε͸ FRVBMTϝιουΛ༻ҙ͍ͯ͠ͳ͍
  41. ·ͱΊ w +6OJUΛ࢖͑͹҆શʹϦϑΝΫλϦϯάͰ͖Δ w ݸਓͰͷϦϑΝΫλϦϯάʹ͸ݶք͕͋ΔͨΊςετίʔυΛॻ ͘จԽΛ࡞Δ w $*Λಋೖͯ͠ςετίʔυΛڧ੍తʹҙࣝͤ͞Δ w ΧόϨοδΛՄࢹԽͯ͠ޮՌతʹςετίʔυ͕ॻ͚͍ͯΔ͔

    ֬ೝͰ͖Δ؀ڥΛ࡞Δ w ςετίʔυΛָʹ͢ΔϥΠϒϥϦΛಋೖͯ͠ɺςετίʔυ ࡞੒΁ͷϋʔυϧΛԼ͛Δ
  42. ͝੩ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠ɻ