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

XUTPから学ぶ記述性の高いユニットテスト 〜俺たちを助けるユニットテストへ〜 / xUTP in #xpjug

PoohSunny
September 15, 2017

XUTPから学ぶ記述性の高いユニットテスト 〜俺たちを助けるユニットテストへ〜 / xUTP in #xpjug

XP祭り2017での発表資料です。
http://xpjug.com/xp2017/

PoohSunny

September 15, 2017
Tweet

More Decks by PoohSunny

Other Decks in Technology

Transcript

  1. ΄Μ·͢·Μ͔ͬͨ class WorkingTimeCalculatorTest { @Test void ਖ਼ৗܥͷςετ() throws Exception {

    // (ུ) Contract contract = new Contract(); User targetUser = new User(contract); LocalDateTime workingStartTime1 = LocalDateTime.of(2017, 9, 1, 10, 00); LocalDateTime workingEndTime1 = LocalDateTime.of(2017, 9, 1, 18, 00); LocalDateTime workingStartTime2 = LocalDateTime.of(2017, 9, 1, 22, 00); LocalDateTime workingEndTime2 = LocalDateTime.of(2017, 9, 2, 4, 00); WorkingTimeCalculator target = new WorkingTimeCalculator(targetUser, workingStartTime1, workingEndTime1, workingStartTime2, workingEndTime2); Class<WorkingTimeCalculator> c = WorkingTimeCalculator.class; Method m = c.getDeclaredMethod("calculation", null); m.setAccessible(true); m.invoke(target, null); CalculationResult result = target.getCaluculationResult(); assertEquals(720, result.getWorkTime()); List<Integer> breakTimeList = result.getBreakTimeList(); assertEquals(2, breakTimeList.size()); assertEquals(60, breakTimeList[0]); assertEquals(45, breakTimeList[1]); } } 8
  2. ·ͣ΍Δ͜ͱ class WorkingTimeCalculatorTest { @Test void ਖ਼ৗܥͷςετ() throws Exception {

    // (ུ) Contract contract = new Contract(); User targetUser = new User(contract); LocalDateTime workingStartTime1 = LocalDateTime.of(2017, 9, 1, 10, 00); LocalDateTime workingEndTime1 = LocalDateTime.of(2017, 9, 1, 18, 00); LocalDateTime workingStartTime2 = LocalDateTime.of(2017, 9, 1, 22, 00); LocalDateTime workingEndTime2 = LocalDateTime.of(2017, 9, 2, 4, 00); WorkingTimeCalculator target = new WorkingTimeCalculator(targetUser, workingStartTime1, workingEndTime1, workingStartTime2, workingEndTime2); Class<WorkingTimeCalculator> c = WorkingTimeCalculator.class; Method m = c.getDeclaredMethod("calculation", null); m.setAccessible(true); m.invoke(target, null); CalculationResult result = target.getCaluculationResult(); assertEquals(720, result.getWorkTime()); List<Integer> breakTimeList = result.getBreakTimeList(); assertEquals(2, breakTimeList.size()); assertEquals(60, breakTimeList[0]); assertEquals(45, breakTimeList[1]); } } 16
  3. ͜Εͳʹͯ͠Δͷʁ class WorkingTimeCalculatorTest { @Test void ਖ਼ৗܥͷςετ() throws Exception {

    // (ུ) Contract contract = new Contract(); User targetUser = new User(contract); LocalDateTime workingStartTime1 = LocalDateTime.of(2017, 9, 1, 10, 00); LocalDateTime workingEndTime1 = LocalDateTime.of(2017, 9, 1, 18, 00); LocalDateTime workingStartTime2 = LocalDateTime.of(2017, 9, 1, 22, 00); LocalDateTime workingEndTime2 = LocalDateTime.of(2017, 9, 2, 4, 00); WorkingTimeCalculator target = new WorkingTimeCalculator(targetUser, workingStartTime1, workingEndTime1, workingStartTime2, workingEndTime2); Class<WorkingTimeCalculator> c = WorkingTimeCalculator.class; Method m = c.getDeclaredMethod("calculation", null); m.setAccessible(true); m.invoke(target, null); CalculationResult result = target.getCaluculationResult(); assertEquals(720, result.getWorkTime()); List<Integer> breakTimeList = result.getBreakTimeList(); assertEquals(2, breakTimeList.size()); assertEquals(60, breakTimeList[0]); assertEquals(45, breakTimeList[1]); } } 17
  4. ߏ଄Խ͍ͯ͠ͳ͍ class WorkingTimeCalculatorTest { @DisplayName("1೔ʹෳ਺ۈ຿ͨ͠ࡍͷۈ຿࣌ؒͷ߹ܭͱٳܜ͕࣌ؒܭࢉ͞ΕΔ΂͖⏰") @Test void workingTimeCalculationTest() throws Exception

    { // (ུ) Contract contract = new Contract(); User targetUser = new User(contract); LocalDateTime workingStartTime1 = LocalDateTime.of(2017, 9, 1, 10, 00); LocalDateTime workingEndTime1 = LocalDateTime.of(2017, 9, 1, 18, 00); LocalDateTime workingStartTime2 = LocalDateTime.of(2017, 9, 1, 22, 00); LocalDateTime workingEndTime2 = LocalDateTime.of(2017, 9, 2, 4, 00); WorkingTimeCalculator target = new WorkingTimeCalculator(targetUser, workingStartTime1, workingEndTime1, workingStartTime2, workingEndTime2); Class<WorkingTimeCalculator> c = WorkingTimeCalculator.class; Method m = c.getDeclaredMethod("calculation", null); m.setAccessible(true); m.invoke(target, null); CalculationResult result = target.getCaluculationResult(); assertEquals(720, result.getWorkTime()); List<Integer> breakTimeList = result.getBreakTimeList(); assertEquals(2, breakTimeList.size()); assertEquals(60, breakTimeList[0]); assertEquals(45, breakTimeList[1]); } } 23
  5. ߏ଄Խ͍Ζ͍Ζ 4 phase 3A7 BDD Spock setup arrange given given

    exercise act when - verify assert then expect teardown - - - 7 http://xp123.com/articles/3a-arrange-act-assert/ 26
  6. Given-When-Then class WorkingTimeCalculatorTest { @DisplayName("1೔ʹෳ਺ۈ຿ͨ͠ࡍͷۈ຿࣌ؒͷ߹ܭͱٳܜ͕࣌ؒܭࢉ͞ΕΔ΂͖⏰") @Test void workingTimeCalculationTest() throws Exception

    { // given Contract contract = new Contract(); User targetUser = new User(contract); LocalDateTime workingStartTime1 = LocalDateTime.of(2017, 9, 1, 10, 00); LocalDateTime workingEndTime1 = LocalDateTime.of(2017, 9, 1, 18, 00); LocalDateTime workingStartTime2 = LocalDateTime.of(2017, 9, 1, 22, 00); LocalDateTime workingEndTime2 = LocalDateTime.of(2017, 9, 2, 4, 00); // when WorkingTimeCalculator target = new WorkingTimeCalculator(targetUser, workingStartTime1, workingEndTime1, workingStartTime2, workingEndTime2); Class<WorkingTimeCalculator> c = WorkingTimeCalculator.class; Method m = c.getDeclaredMethod("calculation", null); m.setAccessible(true); m.invoke(target, null); CalculationResult result = target.getCaluculationResult(); // then assertEquals(720, result.getWorkTime()); List<Integer> breakTimeList = result.getBreakTimeList(); assertEquals(2, breakTimeList.size()); assertEquals(60, breakTimeList[0]); assertEquals(45, breakTimeList[1]); } } 27
  7. Given // given Contract contract = new Contract(); User targetUser

    = new User(contract); LocalDateTime workingStartTime1 = LocalDateTime.of(2017, 9, 1, 10, 00); LocalDateTime workingEndTime1 = LocalDateTime.of(2017, 9, 1, 18, 00); LocalDateTime workingStartTime2 = LocalDateTime.of(2017, 9, 1, 22, 00); LocalDateTime workingEndTime2 = LocalDateTime.of(2017, 9, 2, 4, 00); 28
  8. When WorkingTimeCalculator target = new WorkingTimeCalculator(targetUser, workingStartTime1, workingEndTime1, workingStartTime2, workingEndTime2);

    Class<WorkingTimeCalculator> c = WorkingTimeCalculator.class; Method m = c.getDeclaredMethod("calculation", null); m.setAccessible(true); m.invoke(target, null); CalculationResult result = target.getCaluculationResult(); 29
  9. Then // then assertEquals(720, result.getWorkTime()); List<Integer> breakTimeList = result.getBreakTimeList(); assertEquals(2,

    breakTimeList.size()); assertEquals(60, breakTimeList[0]); assertEquals(45, breakTimeList[1]); 30
  10. ෳ਺ͷΞαʔγϣϯ // then assertEquals(720, result.getWorkTime()); List<Integer> breakTimeList = result.getBreakTimeList(); assertEquals(2,

    breakTimeList.size()); assertEquals(60, breakTimeList[0]); assertEquals(45, breakTimeList[1]); 32
  11. ରࡦ: γϯάϧΞαʔγϣϯ9 • ࿑ಇ࣌ؒܭࢉͷςετ // then assertEquals(720, result.getWorkTime()); • ٳܜ࣌ؒܭࢉͷςετ

    // then List<Integer> breakTimeList = result.getBreakTimeList(); assertEquals(2, breakTimeList.size()); assertEquals(60, breakTimeList[0]); assertEquals(45, breakTimeList[1]); 9 http://xunitpatterns.com/Principles%20of%20Test%20Automation.html#Single Condition Test 34
  12. ಡΈ΍͍͢ܗʹ ϦϑΝΫλϦϯά • ྫ͑͹JUnit5 + AssertJΛར༻ // then List<Integer> breakTimeList

    = result.getBreakTimeList(); assertThat(breakTimeList).hasSize(2).containsExactly(60, 45); 36
  13. ಡΈ΍͘͢ͳΒͳ͍Α͏ͳΒ ΋͠ಡΈ΍͘͢ͳΒͳ͍ͳΒɺγϯάϧΞαʔγ ϣϯਥʹͳΔͭ΋Γ͸ͳ͍Α — Principle: Verify One Condition per Test

    11 11 http://xunitpatterns.com/Principles%20of%20Test%20Automation.html#Single Condition Test ΑΓҙ༁ 40
  14. Then͸׬ྃ // given Contract contract = new Contract(); User targetUser

    = new User(contract); LocalDateTime workingStartTime1 = LocalDateTime.of(2017, 9, 1, 10, 00); LocalDateTime workingEndTime1 = LocalDateTime.of(2017, 9, 1, 18, 00); LocalDateTime workingStartTime2 = LocalDateTime.of(2017, 9, 1, 22, 00); LocalDateTime workingEndTime2 = LocalDateTime.of(2017, 9, 2, 4, 00); // when WorkingTimeCalculator target = new WorkingTimeCalculator(targetUser, workingStartTime1, workingEndTime1, workingStartTime2, workingEndTime2); Class<WorkingTimeCalculator> c = WorkingTimeCalculator.class; Method m = c.getDeclaredMethod("calculation", null); m.setAccessible(true); m.invoke(target, null); CalculationResult result = target.getCaluculationResult(); // then List<Integer> breakTimeList = result.getBreakTimeList(); ٳܜ͸2ճ෼ܭࢉ͞Εͯ(breakTimeList, _1ͭ໨ͷܭࢉ࣌ؒ͸(60), _2ͭ໨ͷܭࢉ࣌ؒ͸(45)); 41
  15. ଓ͍ͯWhen // when WorkingTimeCalculator target = new WorkingTimeCalculator(targetUser, workingStartTime1, workingEndTime1,

    workingStartTime2, workingEndTime2); Class<WorkingTimeCalculator> c = WorkingTimeCalculator.class; Method m = c.getDeclaredMethod("calculation", null); m.setAccessible(true); m.invoke(target, null); CalculationResult result = target.getCaluculationResult(); 42
  16. ϦϑϨΫγϣϯʁ // when Class<WorkingTimeCalculator> c = WorkingTimeCalculator.class; Method m =

    c.getDeclaredMethod("calculation", null); m.setAccessible(true); m.invoke(target, null); 43
  17. Test-Specific Subclass12 // ςετ಺ʹϔϧύʔͱͯ͠ class WorkingCaluculatorForTest extends WorkingCaluculator { public

    calucuation() { super.caluculation(); } } // ςετଆ͸ݺͿ͚ͩ workingCalculator.calucuation(); 12 http://xunitpatterns.com/Test-Specific%20Subclass.html 46
  18. When׬ྃ class WorkingTimeCalculatorTest { @DisplayName("1೔ʹෳ਺ۈ຿ͨ͠ࡍͷۈ຿࣌ؒͷ߹ܭͱٳܜ͕࣌ؒܭࢉ͞ΕΔ΂͖⏰") @Test void workingTimeCalculationTest() throws Exception

    { // given Contract contract = new Contract(); User targetUser = new User(contract); LocalDateTime workingStartTime1 = LocalDateTime.of(2017, 9, 1, 10, 00); LocalDateTime workingEndTime1 = LocalDateTime.of(2017, 9, 1, 18, 00); LocalDateTime workingStartTime2 = LocalDateTime.of(2017, 9, 1, 22, 00); LocalDateTime workingEndTime2 = LocalDateTime.of(2017, 9, 2, 4, 00); // when workingCalculator.calucuation(); CalculationResult result = target.getCaluculationResult(); // then List<Integer> breakTimeList = result.getBreakTimeList(); ٳܜ͸2ճ෼ܭࢉ͞Εͯ(breakTimeList, _1ͭ໨ͷܭࢉ࣌ؒ͸(60), _2ͭ໨ͷܭࢉ࣌ؒ͸(45)); } } 47
  19. ࠷ޙʹGiven // given Contract contract = new Contract(); User targetUser

    = new User(contract); LocalDateTime workingStartTime1 = LocalDateTime.of(2017, 9, 1, 10, 00); LocalDateTime workingEndTime1 = LocalDateTime.of(2017, 9, 1, 18, 00); LocalDateTime workingStartTime2 = LocalDateTime.of(2017, 9, 1, 22, 00); LocalDateTime workingEndTime2 = LocalDateTime.of(2017, 9, 2, 4, 00); 48
  20. ࣅͨΑ͏ͳσʔληοτ LocalDateTime workingStartTime1 = LocalDateTime.of(2017, 9, 1, 10, 00); LocalDateTime

    workingEndTime1 = LocalDateTime.of(2017, 9, 1, 18, 00); LocalDateTime workingStartTime2 = LocalDateTime.of(2017, 9, 1, 22, 00); LocalDateTime workingEndTime2 = LocalDateTime.of(2017, 9, 2, 4, 00); 49
  21. Creation Methodʹͯ͠ ෆཁ৘ใΛӅṭ LocalDateTime workingStartTime1 = createFirstWorkStartTime(); LocalDateTime workingEndTime1 =

    createFirstWorkEndTime(); LocalDateTime workingStartTime2 = createSecondWorkStartTime(); LocalDateTime workingEndTime2 = createSecondWorkEndTime(); 52
  22. ೔ຊޠʹ͢Δͷ΋ΞϦ LocalDateTime ࠷ॳͷۈ຿ͷ։࢝࣌ؒ = ࠷ॳͷۈ຿ͷ։࢝࣌ؒΛ࡞੒(); LocalDateTime ࠷ॳͷۈ຿ͷऴྃ࣌ؒ = ࠷ॳͷۈ຿ͷऴྃ࣌ؒΛ࡞੒(); LocalDateTime

    ೋͭ໨ͷۈ຿ͷ։࢝࣌ؒ = ೋͭ໨ͷۈ຿ͷ։࢝࣌ؒΛ࡞੒(); LocalDateTime ೋͭ໨ͷۈ຿ͷऴྃ࣌ؒ = ೋͭ໨ͷۈ຿ͷऴྃ࣌ؒΛ࡞੒(); 53
  23. Given // given(ུ) Contract contract = new Contract(); User targetUser

    = new User(contract); LocalDateTime ࠷ॳͷۈ຿ͷ։࢝࣌ؒ = ࠷ॳͷۈ຿ͷ։࢝࣌ؒΛ࡞੒(); LocalDateTime ࠷ॳͷۈ຿ͷऴྃ࣌ؒ = ࠷ॳͷۈ຿ͷऴྃ࣌ؒΛ࡞੒(); LocalDateTime ೋͭ໨ͷۈ຿ͷ։࢝࣌ؒ = ೋͭ໨ͷۈ຿ͷ։࢝࣌ؒΛ࡞੒(); LocalDateTime ೋͭ໨ͷۈ຿ͷऴྃ࣌ؒ = ೋͭ໨ͷۈ຿ͷऴྃ࣌ؒΛ࡞੒(); 54
  24. Ϣʔβʔͷ࡞੒΋ // given(ུ) Contract contract = new Contract(); User targetUser

    = new User(contract); ܖ໿಺༰Λ࡞੒Λ໌ࣔ͢Δඞཁ͸ͳ͍ // given User ਖ਼ࣾһͷϢʔβʔ = ਖ਼ࣾһͷϢʔβʔͷ࡞੒(); 55
  25. Ұ࣌ม਺ඞཁʁ // given User ਖ਼ࣾһͷϢʔβʔ = ਖ਼ࣾһͷϢʔβʔͷ࡞੒(); LocalDateTime ࠷ॳͷۈ຿ͷ։࢝࣌ؒ =

    ࠷ॳͷۈ຿ͷ։࢝࣌ؒΛ࡞੒(); LocalDateTime ࠷ॳͷۈ຿ͷऴྃ࣌ؒ = ࠷ॳͷۈ຿ͷऴྃ࣌ؒΛ࡞੒(); LocalDateTime ೋͭ໨ͷۈ຿ͷ։࢝࣌ؒ = ೋͭ໨ͷۈ຿ͷ։࢝࣌ؒΛ࡞੒(); LocalDateTime ೋͭ໨ͷۈ຿ͷऴྃ࣌ؒ = ೋͭ໨ͷۈ຿ͷऴྃ࣌ؒΛ࡞੒(); WorkingTimeCalculator target = new WorkingTimeCalculatorForTest(ਖ਼ࣾһͷϢʔβʔ, ࠷ॳͷۈ຿ͷ։࢝࣌ؒ, ࠷ॳͷۈ຿ͷऴྃ࣌ؒ, ೋͭ໨ͷۈ຿ͷ։࢝࣌ؒ, ೋͭ໨ͷۈ຿ͷऴྃ࣌ؒ); 56
  26. Ұ࣌ม਺Λফڈ // given WorkingTimeCalculator target = new WorkingTimeCalculatorForTest( ਖ਼ࣾһͷϢʔβʔͷ࡞੒(), ࠷ॳͷۈ຿ͷ։࢝࣌ؒΛ࡞੒(),

    ࠷ॳͷۈ຿ͷऴྃ࣌ؒΛ࡞੒(), ೋͭ໨ͷۈ຿ͷ։࢝࣌ؒΛ࡞੒(), ೋͭ໨ͷۈ຿ͷऴྃ࣌ؒΛ࡞੒()); 57
  27. implicit setup14 class WorkingTimeCalculatorTest { WorkingTimeCalculator target = null; @BeforeEach

    void WorkingTimeCalculatorͷ࡞੒() { // given target = new WorkingTimeCalculatorForTest( ਖ਼ࣾһͷϢʔβʔͷ࡞੒(), ࠷ॳͷۈ຿ͷ։࢝࣌ؒΛ࡞੒(), ࠷ॳͷۈ຿ͷऴྃ࣌ؒΛ࡞੒(), ೋͭ໨ͷۈ຿ͷ։࢝࣌ؒΛ࡞੒(), ೋͭ໨ͷۈ຿ͷऴྃ࣌ؒΛ࡞੒()); } @DisplayName("ෳ਺ۈ຿ͨ͠ࡍͷۈ຿࣌ؒͷ߹ܭͱٳܜ͕࣌ؒܭࢉ͞ΕΔ΂͖⏰") 14 http://xunitpatterns.com/Implicit%20Setup.html 58
  28. ׬੒ class WorkingTimeCalculatorTest { WorkingTimeCalculator target = null; @BeforeEach void

    WorkingTimeCalculatorͷ࡞੒() { // given target = new WorkingTimeCalculatorForTest( ਖ਼ࣾһͷϢʔβʔͷ࡞੒(), ࠷ॳͷۈ຿ͷ։࢝࣌ؒΛ࡞੒(), ࠷ॳͷۈ຿ͷऴྃ࣌ؒΛ࡞੒(), ೋͭ໨ͷۈ຿ͷ։࢝࣌ؒΛ࡞੒(), ೋͭ໨ͷۈ຿ͷऴྃ࣌ؒΛ࡞੒()); } @DisplayName("ෳ਺ۈ຿ͨ͠ࡍͷۈ຿࣌ؒͷ߹ܭͱٳܜ͕࣌ؒܭࢉ͞ΕΔ΂͖⏰") @Test void breakTimeCalculation() throws Exception { // when workingCalculator.calucuation(); CalculationResult result = target.getCaluculationResult(); // then List<Integer> breakTimeList = result.getBreakTimeList(); ٳܜ͸2ճ෼ܭࢉ͞Εͯ(breakTimeList, _1ͭ໨ͷܭࢉ࣌ؒ͸(60), _2ͭ໨ͷܭࢉ࣌ؒ͸(45)); } } 59
  29. ࠷ॳͷ࣌ͱൺֱ͢Δͱ class WorkingTimeCalculatorTest { @Test void ਖ਼ৗܥͷςετ() throws Exception {

    // (ུ) Contract contract = new Contract(); User targetUser = new User(contract); LocalDateTime workingStartTime1 = LocalDateTime.of(2017, 9, 1, 10, 00); LocalDateTime workingEndTime1 = LocalDateTime.of(2017, 9, 1, 18, 00); LocalDateTime workingStartTime2 = LocalDateTime.of(2017, 9, 1, 22, 00); LocalDateTime workingEndTime2 = LocalDateTime.of(2017, 9, 2, 4, 00); WorkingTimeCalculator target = new WorkingTimeCalculator(targetUser, workingStartTime1, workingEndTime1, workingStartTime2, workingEndTime2); Class<WorkingTimeCalculator> c = WorkingTimeCalculator.class; Method m = c.getDeclaredMethod("calculation", null); m.setAccessible(true); m.invoke(target, null); CalculationResult result = target.getCaluculationResult(); assertEquals(720, result.getWorkTime()); List<Integer> breakTimeList = result.getBreakTimeList(); assertEquals(2, breakTimeList.size()); assertEquals(60, breakTimeList[0]); assertEquals(45, breakTimeList[1]); } } 60
  30. ಡΈ΍͘͢ͳͬͨ @DisplayName("ෳ਺ۈ຿ͨ͠ࡍͷۈ຿࣌ؒͷ߹ܭͱٳܜ͕࣌ؒܭࢉ͞ΕΔ΂͖⏰") @Test void breakTimeCalculation() throws Exception { // when

    workingCalculator.calucuation(); CalculationResult result = sut.getCaluculationResult(); // then List<Integer> breakTimeList = result.getBreakTimeList(); ٳܜ͸2ճ෼ܭࢉ͞Εͯ(breakTimeList, _1ͭ໨ͷܭࢉ࣌ؒ͸(60), _2ͭ໨ͷܭࢉ࣌ؒ͸(45)); 61
  31. One more thing • ςετର৅ΛSUT(System Under Test)ͱهड़ ͢Δͷ͸xUTPจԽ15 CalculationResult result

    = sut.getCaluculationResult(); 15 http://xunitpatterns.com/SUT.html 62