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

SpekでUnitTestを書こう / unit-test-with-spek

0f9e5363528f70e1b274f24ada191eb8?s=47 moriiimo
February 08, 2019

SpekでUnitTestを書こう / unit-test-with-spek

0f9e5363528f70e1b274f24ada191eb8?s=128

moriiimo

February 08, 2019
Tweet

Transcript

  1. 4QFLͰ6OJU5FTUΛॻ͜͏ "ZBLP.PSJNPUP!NPSJJJNP

  2. ʘ࠷ۙϦχϡʔΞϧ͠·ͨ͠ʗ "ZBLP.PSJNPUP %..DPNMJGF ࣄۀ෦ ࣗݾ঺հ

  3. None
  4. 4QFLΛ஌Γɺ ςετΛॻ͖͍ͨͱࢥͬͯ΋Β͏͜ͱ ΰʔϧ

  5. ຊ೔͓࿩͢Δ͜ͱ 4QFLͱ͸ʁ 4QFLͰ6OJU5FTUΛॻ͍ͯΈΑ͏ Ԡ༻ฤ4QFLͰ-JWF%BUB΍3PPNͷ 6OJU5FTUΛॻ͍ͯΈΑ͏

  6. ຊ೔͓࿩͢Δ͜ͱ 4QFLͱ͸ʁ 4QFLͰ6OJU5FTUΛॻ͍ͯΈΑ͏ Ԡ༻ฤ4QFLͰ-JWF%BUB΍3PPNͷ 6OJU5FTUΛॻ͍ͯΈΑ͏

  7. ຊ೔͓࿩͢Δ͜ͱ 4QFLͱ͸ʁ 4QFLͰ6OJU5FTUΛॻ͍ͯΈΑ͏ Ԡ༻ฤ4QFLͰ-JWF%BUB΍3PPNͷ 6OJU5FTUΛॻ͍ͯΈΑ͏

  8. ຊ೔͓࿩͢Δ͜ͱ 4QFLͱ͸ʁ 4QFLͰ6OJU5FTUΛॻ͍ͯΈΑ͏ Ԡ༻ฤ4QFLͰ-JWF%BUB΍3PPNͷ 6OJU5FTUΛॻ͍ͯΈΑ͏

  9. 4QFLͱ͸ʁ

  10. Copyright (c) 2018, Spek Core Team and Contributors

  11. l5IJTTUZMFJTJOTQJSFECZUFTUGSBNFXPSLTMJLF +BTNJOFBOE34QFDz IUUQTTQFLGSBNFXPSLPSHTQFDJpDBUJPO

  12. l5IJTTUZMFJTJOTQJSFECZUFTUGSBNFXPSLTMJLF +BTNJOFBOE34QFDz IUUQTTQFLGSBNFXPSLPSHTQFDJpDBUJPO +BWB4DSJQU

  13. l5IJTTUZMFJTJOTQJSFECZUFTUGSBNFXPSLTMJLF +BTNJOFBOE34QFDz IUUQTTQFLGSBNFXPSLPSHTQFDJpDBUJPO 3VCZ

  14. l5IJTTUZMFJTJOTQJSFECZUFTUGSBNFXPSLTMJLF +BTNJOFBOE34QFDz IUUQTTQFLGSBNFXPSLPSHTQFDJpDBUJPO

  15. 5PEP$MBTT class Todo(val id: Int) { constructor(id: Int, label: String,

    complete: Boolean, deadline: Long) : this(id) { this.label = label this.complete = complete this.deadline = deadline } var label: String = "" private set var complete: Boolean = false private set var deadline: Long = System.currentTimeMillis() private set }
  16. 5PEP$MBTT fun checkComplete() { complete = true } fun unCheckComplete()

    { complete = false } ऴྃঢ়ଶͷ มߋ͕Ͱ͖ͨΓʜ
  17. 5PEP$MBTT fun addDayToDeadline(numOfDays: Int) { changeDeadline(numOfDays) } fun reduceDayToDeadline(numOfDays: Int)

    { changeDeadline(-numOfDays) } private fun changeDeadline(numOfDays: Int) { deadline = Calendar.getInstance(TimeZone.getDefault(), Locale.JAPAN).apply { timeInMillis = deadline add(Calendar.DATE, numOfDays) }.timeInMillis } ظݶͷมߋ͕ Ͱ͖ͨΓ͠·͢
  18. +6OJU5PEP5FTU class TodoTest { private val now = System.currentTimeMillis() private

    lateinit var todo: Todo @Before fun setup() { todo = Todo(id = 1, label = "Write Unit Test with Spek", complete = false, deadline = now ) } @Test fun changeCompleteStatus_shouldBeTrue() { todo.checkComplete() assertTrue(todo.complete) } @Test fun changeCompleteStatus_shouldBeFalse() { todo.unCheckComplete() assertFalse(todo.complete) } @Test fun addDaysToDeadline_shouldBeThreeDaysLater() { val expect = Calendar.getInstance(TimeZone.getDefault(), Locale.JAPAN).apply { timeInMillis = now add(Calendar.DATE, 3) } todo.addDayToDeadline(3) assertEquals(expect.timeInMillis, todo.deadline) } @Test fun reduceDaysToDeadline_shouldBeThreeDaysAgo() { val expect = Calendar.getInstance(TimeZone.getDefault(), Locale.JAPAN).apply { timeInMillis = now add(Calendar.DATE, -3) } todo.reduceDayToDeadline(3) assertEquals(expect.timeInMillis, todo.deadline) } }
  19. ݟͮΒ͍ϙΠϯτ @Test fun changeFinishStatus_shouldBeTrue() { todo.checkComplete() assert(todo.complete) }

  20. ݟͮΒ͍ϙΠϯτ ϝιου໊΍ίϝϯτͰ ૝ఆΛද͢ඞཁ͕͋Δ @Test fun changeFinishStatus_shouldBeTrue() { todo.checkComplete() assert(todo.complete) }

  21. ݟͮΒ͍ϙΠϯτ @Test fun changeFinishStatus_shouldBeTrue() { todo.checkComplete() assert(todo.complete) }

  22. ݟͮΒ͍ϙΠϯτ @Test fun changeCompleteStatus_shouldBeTrue() { todo.checkComplete() assertTrue(todo.complete) } @Test fun

    changeCompleteStatus_shouldBeFalse() { todo.unCheckComplete() assertFalse(todo.complete) }
  23. ݟͮΒ͍ϙΠϯτ @Test fun changeCompleteStatus_shouldBeTrue() { todo.checkComplete() assertTrue(todo.complete) } @Test fun

    changeCompleteStatus_shouldBeFalse() { todo.unCheckComplete() assertFalse(todo.complete) } @Test fun addDaysToDeadline_shouldBeThreeDaysLater() { val expect = Calendar.getInstance(TimeZone.getDefault(), Locale.JAPAN).apply { timeInMillis = now add(Calendar.DATE, 3) } todo.addDayToDeadline(3) assertEquals(expect.timeInMillis, todo.deadline) }
  24. ݟͮΒ͍ϙΠϯτ @Test fun changeCompleteStatus_shouldBeTrue() { todo.checkComplete() assertTrue(todo.complete) } @Test fun

    changeCompleteStatus_shouldBeFalse() { todo.unCheckComplete() assertFalse(todo.complete) } @Test fun addDaysToDeadline_shouldBeThreeDaysLater() { val expect = Calendar.getInstance(TimeZone.getDefault(), Locale.JAPAN).apply { timeInMillis = now add(Calendar.DATE, 3) } todo.addDayToDeadline(3) assertEquals(expect.timeInMillis, todo.deadline) } @Test fun reduceDaysToDeadline_shouldBeThreeDaysAgo() { val expect = Calendar.getInstance(TimeZone.getDefault(), Locale.JAPAN).apply { timeInMillis = now add(Calendar.DATE, -3) } todo.reduceDayToDeadline(3) assertEquals(expect.timeInMillis, todo.deadline) } ΧςΰϥΠζɺ ֊૚ԽͰ͖ͳ͍
  25. ݟͮΒ͍ϙΠϯτ @Test fun changeFinishStatus_shouldBeTrue() { todo.markFinished() assert(todo.finished) } @Test fun

    changeFinishStatus_shouldBeFalse() { todo.markUnFinished() assert(!todo.finished) } @Test fun addDaysToDeadline_shouldBeThreeDaysLater() { val expect = Calendar.getInstance(TimeZone.getDefault(), Locale.JAPAN).apply { timeInMillis = now add(Calendar.DATE, 3) } todo.addDayToDeadline(3) assertEquals(expect.timeInMillis, todo.deadline) } @Test fun reduceDaysToDeadline_shouldBeThreeDaysAgo() { val expect = Calendar.getInstance(TimeZone.getDefault(), Locale.JAPAN).apply { timeInMillis = now add(Calendar.DATE, -3) } todo.reduceDayToDeadline(3) assertEquals(expect.timeInMillis, todo.deadline) } ࣮ߦॱং͕อূ ͞Εͳ͍
  26. 4QFL5PEP5FTU class TodoFeature : Spek({ Feature("Todo") { val now =

    System.currentTimeMillis() lateinit var todo: Todo Scenario("complete status") { Given("the todo is not complete") { todo = Todo( id = 1, label = "", deadline = now, complete = false ) } When("complete the todo") { todo.checkComplete() } Then("the todo is complete") { assertTrue(todo.complete) } When("return the todo to incomplete") { todo.unCheckComplete() } Then("the todo is not complete") { assertTrue(!todo.complete) } } } })
  27. ݟ΍͍͢ϙΠϯτ Scenario("complete status") { Given("the todo is not complete") {

    todo = Todo( id = 1, label = "", deadline = now, complete = false ) } When("complete the todo") { todo.checkComplete() } Then("the todo is complete") { assertTrue(todo.complete) } }
  28. ݟ΍͍͢ϙΠϯτ Scenario("complete status") { Given("the todo is not complete") {

    todo = Todo( id = 1, label = "", deadline = now, complete = false ) } When("complete the todo") { todo.checkComplete() } Then("the todo is complete") { assertTrue(todo.complete) } } ૝ఆ͕ ॻ͖΍͍͢
  29. ิ଍ Scenario("changing todo finish status") { Given("todo is not finish")

    { todo = Todo( id = 1, label = "Write Unit Test with Spek", finished = false, deadline = now ) } When("mark finish") { todo.markFinished() } Then("it should be true") { assertTrue(todo.finished) } } ૝ఆ͕ ॻ͖΍͍͢ ͪͳΈʹʜ͜ͷΑ͏ͳه๏͸(IFSLJOͱ͍͏ ςετهड़ݴޠϑΥʔϚοτ͕ݩʹͳ͍ͬͯ·͢
  30. ิ଍ Scenario("changing todo finish status") { Given("todo is not finish")

    { todo = Todo( id = 1, label = "Write Unit Test with Spek", finished = false, deadline = now ) } When("mark finish") { todo.markFinished() } Then("it should be true") { assertTrue(todo.finished) } } ૝ఆ͕ ॻ͖΍͍͢ ͪͳΈʹʜ͜ͷΑ͏ͳه๏͸(IFSLJOͱ͍͏ ςετهड़ݴޠϑΥʔϚοτ͕ݩʹͳ͍ͬͯ·͢ ػೳ50%0 γφϦΦऴྃεςʔλε͕ਖ਼͘͠มԽ͢Δ લఏ50%0ͷऴྃεςʔλε͕ະ׬ྃ ΋͠50%0ͷऴྃεςʔλεΛ׬ྃʹͨ͠Β ͳΒ͹50%0ͷऴྃεςʔλε͕׬ྃʹͳΔ ೔ຊޠͰ΋͔͚ͯɺ ॻ͘ͱ͜Μͳײ͡ʹͳΔ
  31. ݟ΍͍͢ϙΠϯτ class TodoFeature : Spek({ Feature("Todo") { Scenario(“complete status") {

    . . . ऴྃεςʔλεͷςετ } Scenario("deadline") { . . . క੾ͷςετ } Scenario(“label") { . . . ໊લͷςετ } } })
  32. ݟ΍͍͢ϙΠϯτ class TodoFeature : Spek({ Feature("Todo") { Scenario(“complete status") {

    . . . ऴྃεςʔλεͷςετ } Scenario("deadline") { . . . క੾ͷςετ } Scenario(“label") { . . . ໊લͷςετ } } }) Θ͔Γ΍͘͢Χςΰ ϥΠζͰ͖Δ
  33. class TodoFeature : Spek({ Feature("Todo") { Scenario("changing finish status") {

    . . . ऴྃεςʔλεͷςετ } Scenario("changing deadline") { . . . క੾มߋͷςετ } Scenario("changing label") { . . . ໊લมߋͷςετ } } }) ݟ΍͍͢ϙΠϯτ ࣮ߦॱং͕อূ͞ΕΔ
  34. 4QFLͰ6OJU5FTUΛ ॻ͍ͯΈΑ͏

  35. ηοτΞοϓ https://spekframework.org/setup-android/

  36. ηοτΞοϓ https://spekframework.org/setup-android/ ๨Εͣʹ΍ͬͯ΄͍͠ͷ͕…

  37. ηοτΞοϓ https://spekframework.org/setup-android/ ๨Εͣʹ΍ͬͯ΄͍͠ͷ͕… #1 SpekͷAndroidStudioϓϥάΠϯΛೖΕ·͠ΐ͏

  38. ηοτΞοϓ https://spekframework.org/setup-android/ ๨Εͣʹ΍ͬͯ΄͍͠ͷ͕… #1 SpekͷAndroidStudioϓϥάΠϯΛೖΕ·͠ΐ͏ #2 KotlinͷAndroidStudioϓϥάΠϯΛ1.3Ҏ্ʹΞοϓσʔτ͠· ͠ΐ͏

  39. ηοτΞοϓ https://spekframework.org/setup-android/ ๨Εͣʹ΍ͬͯ΄͍͠ͷ͕… #1 SpekͷAndroidStudioϓϥάΠϯΛೖΕ·͠ΐ͏ #2 KotlinͷAndroidStudioϓϥάΠϯΛ1.3Ҏ্ʹΞοϓσʔτ͠· ͠ΐ͏ Yͩͱʜ✗

  40. جຊͷॻ͖ํ class TodoFeature

  41. جຊͷॻ͖ํ class TodoFeature : Spek({ })

  42. جຊͷॻ͖ํ class TodoFeature : Spek({ Feature("Todo") { } })

  43. جຊͷॻ͖ํ class TodoFeature : Spek({ Feature("Todo") { val now =

    System.currentTimeMillis() lateinit var todo: Todo } })
  44. جຊͷॻ͖ํ class TodoFeature : Spek({ Feature("Todo") { val now =

    System.currentTimeMillis() val todo: Todo by lazy { Todo(id = 1, label = "Write Unit Test with Spek", complete = false, deadline = now) } } }) MB[Z΋"
  45. جຊͷॻ͖ํ class TodoFeature : Spek({ Feature("Todo") { val now =

    System.currentTimeMillis() lateinit var todo: Todo Scenario("complete status") { } } })
  46. جຊͷॻ͖ํ class TodoFeature : Spek({ Feature("Todo") { val now =

    System.currentTimeMillis() lateinit var todo: Todo Scenario("complete status") { Given(“the todo is not complete") { todo = Todo(id = 1, label = "Write Unit Test with Spek”, complete = false, deadline = now) } } } })
  47. جຊͷॻ͖ํ class TodoFeature : Spek({ Feature("Todo") { val now =

    System.currentTimeMillis() lateinit var todo: Todo Scenario("complete status") { Given(“the todo is not complete") { todo = Todo(id = 1, label = "Write Unit Test with Spek", complete = false, deadline = now) } When(“complete the todo") { todo.checkComplete() } } } })
  48. جຊͷॻ͖ํ class TodoFeature : Spek({ Feature("Todo") { val now =

    System.currentTimeMillis() lateinit var todo: Todo Scenario("complete status") { Given(“the todo is not complete") { todo = Todo(id = 1, label = "Write Unit Test with Spek", complete = false, deadline = now) } When(“complete the todo") { todo.checkComplete() } Then(“the todo is complete”) { assertTrue(todo.complete) } } } })
  49. ϧʔϧ class TodoFeature : Spek({ Feature("xxx") { Scenario("xxx") { .

    . . xxxͷςετ } Scenario("yyy") { . . . yyyͷςετ } } Feature("zzz") { Scenario("zzz") { . . . zzzͷςετ } } }) ෳ਺ͷ'FBUVSFɺ'FBUVSF಺ͷ ෳ਺ͷγφϦΦʁ
  50. ෳ਺ͷ'FBUVSFɺ'FBUVSF಺ͷ ෳ਺ͷγφϦΦʁ ϧʔϧ class TodoFeature : Spek({ Feature("xxx") { Scenario("xxx")

    { . . . xxxͷςετ } Scenario("yyy") { . . . yyyͷςετ } } Feature("zzz") { Scenario("zzz") { . . . zzzͷςετ } } }) "
  51. ϧʔϧ class TodoFeature : Spek({ Feature(“xxx") { Scenario("xxx") { Scenario(“yyy")

    { Given("xxx") { Given(“yyy”) { } } } } } }) γφϦΦ΍(JWFO8IFO 5IFOͷωετʁ
  52. γφϦΦ΍(JWFO8IFO 5IFOͷωετʁ ϧʔϧ class TodoFeature : Spek({ Feature(“xxx") { Scenario("xxx")

    { Scenario(“yyy") { Given("xxx") { Given(“yyy”) { } } } } } }) #
  53. @Synonym(SynonymType.GROUP, prefix = "Feature: ") @Descriptions(Description(DescriptionLocation.VALUE_PARAMETER, 0)) fun GroupBody.Feature(description: String,

    body: FeatureBody.() -> Unit) { group("Feature: $description", defaultCachingMode = CachingMode.GROUP) { body(FeatureBody(this)) } }
  54. @Synonym(SynonymType.GROUP, prefix = "Feature: ") @Descriptions(Description(DescriptionLocation.VALUE_PARAMETER, 0)) fun GroupBody.Feature(description: String,

    body: FeatureBody.() -> Unit) { group("Feature: $description", defaultCachingMode = CachingMode.GROUP) { body(FeatureBody(this)) } } ͜Ε
  55. @Synonym(SynonymType.GROUP, prefix = "Feature: ") @Descriptions(Description(DescriptionLocation.VALUE_PARAMETER, 0)) fun GroupBody.Feature(description: String,

    body: FeatureBody.() -> Unit) { group("Feature: $description", defaultCachingMode = CachingMode.GROUP) { body(FeatureBody(this)) } } @SpekDsl class FeatureBody(val delegate: GroupBody): LifecycleAware by delegate { @Synonym(SynonymType.GROUP, prefix = "Scenario: ") @Descriptions(Description(DescriptionLocation.VALUE_PARAMETER, 0)) fun Scenario(description: String, body: ScenarioBody.() -> Unit) { delegate.group("Scenario: $description”, defaultCachingMode = CachingMode.SCOPE, preserveExecutionOrder = true) { body(ScenarioBody(this)) } } }
  56. @SpekDsl class ScenarioBody(val delegate: GroupBody): LifecycleAware by delegate { fun

    Given(description: String, body: TestBody.() -> Unit) { delegate.test("Given: $description", body = body) } fun When(description: String, body: TestBody.() -> Unit) { delegate.test("When: $description", body = body) } fun Then(description: String, body: TestBody.() -> Unit) { delegate.test("Then: $description", body = body) } fun And(description: String, body: TestBody.() -> Unit) { delegate.test("And: $description", body = body) } }
  57. @SpekDsl class ScenarioBody(val delegate: GroupBody): LifecycleAware by delegate { fun

    Given(description: String, body: TestBody.() -> Unit) { delegate.test("Given: $description", body = body) } fun When(description: String, body: TestBody.() -> Unit) { delegate.test("When: $description", body = body) } fun Then(description: String, body: TestBody.() -> Unit) { delegate.test("Then: $description", body = body) } fun And(description: String, body: TestBody.() -> Unit) { delegate.test("And: $description", body = body) } }
  58. @SpekDsl class ScenarioBody(val delegate: GroupBody): LifecycleAware by delegate { fun

    Given(description: String, body: TestBody.() -> Unit) { delegate.test("Given: $description", body = body) } fun When(description: String, body: TestBody.() -> Unit) { delegate.test("When: $description", body = body) } fun Then(description: String, body: TestBody.() -> Unit) { delegate.test("Then: $description", body = body) } fun And(description: String, body: TestBody.() -> Unit) { delegate.test("And: $description", body = body) } } શ෦ಉ͡ʁ
  59. class TodoFeature : Spek({ Feature("Todo") { val now = System.currentTimeMillis()

    lateinit var todo: Todo Scenario("complete status") { Then(“the todo is not complete") { todo = Todo(id = 1, label = "Write Unit Test with Spek", complete = false, deadline = now) } Then(“complete the todo") { todo.checkComplete() } Then(“the todo is complete”) { assertTrue(todo.complete) } } } }) ͭ·Γ ͜ΕͰ΋0,
  60. class TodoFeature : Spek({ Feature("Todo") { val now = System.currentTimeMillis()

    lateinit var todo: Todo Scenario("changing todo finish status") { Then("todo is not finished ") { todo = Todo(id = 1, label = "Write Unit Test with Spek", finished = false, deadline = now) } Then("mark finish") { todo.markFinished() } Then("it should be true") { assertTrue(todo.finished) } } } }) ॱ൪͸ อূ͞Ε͍ͯΔ @SpekDsl class FeatureBody(val delegate: GroupBody): LifecycleAware by delegate { @Synonym(SynonymType.GROUP, prefix = "Scenario: ") @Descriptions(Description(DescriptionLocation.VALUE_PARAMETER, 0)) fun Scenario(description: String, body: ScenarioBody.() -> Unit) { delegate.group("Scenario: $description”, defaultCachingMode = CachingMode.SCOPE, preserveExecutionOrder = true) { body(ScenarioBody(this)) } } }
  61. $PSF$PODFQU https://spekframework.org/core-concepts/

  62. Ԡ༻ฤ4QFLͰ -JWF%BUB΍3PPNͷ 6OJU5FTUΛॻ͍ͯΈΑ͏

  63. "OESPJEͷน

  64. -JWF%BUB+6OJU -JWF%BUBTFU7BMVF -JWF%BUBQPTU7BMVF ʢ%FGBVMU5BTL&YFDVUFSʣ

  65. -JWF%BUB+6OJU -JWF%BUBTFU7BMVF -JWF%BUBQPTU7BMVF ʢ%FGBVMU5BTL&YFDVUFSʣ KBWBMBOH3VOUJNF&YDFQUJPO.FUIPE HFU.BJO-PPQFSJOBOESPJEPT-PPQFSOPUNPDLFE PS /VMM1PJOUFS&YDFQUJPO KBWBMBOH3VOUJNF&YDFQUJPO.FUIPE HFU.BJO-PPQFSJOBOESPJEPT-PPQFSOPUNPDLFE

    PS /VMM1PJOUFS&YDFQUJPO
  66. -JWF%BUB+6OJU class InstantTaskExecutorRule : TestWatcher() { protected fun starting(description: Description)

    { super.starting(description) ArchTaskExecutor.getInstance().setDelegate(object : TaskExecutor() { override fun executeOnDiskIO(runnable: Runnable) { runnable.run() } override fun postToMainThread(runnable: Runnable) { runnable.run() } override fun isMainThread(): Boolean { return true } }) } protected fun finished(description: Description) { super.finished(description) ArchTaskExecutor.getInstance().setDelegate(null) } }
  67. -JWF%BUB+6OJU class InstantTaskExecutorRule : TestWatcher() { protected fun starting(description: Description)

    { super.starting(description) ArchTaskExecutor.getInstance().setDelegate(object : TaskExecutor() { override fun executeOnDiskIO(runnable: Runnable) { runnable.run() } override fun postToMainThread(runnable: Runnable) { runnable.run() } override fun isMainThread(): Boolean { return true } }) } protected fun finished(description: Description) { super.finished(description) ArchTaskExecutor.getInstance().setDelegate(null) } } UFTU*NQMFNFOUBUJPOlBOESPJEBSDIDPSFDPSFUFTUJOH7&34*0/
  68. -JWF%BUB+6OJU @Rule @JvmField val instantTaskExecutorRule = InstantTaskExecutorRule() ˏ3VMFͰࢦఆ

  69. -JWF%BUB+6OJU fun GroupBody.useLiveData() { androidx.arch.core.executor.ArchTaskExecutor.getInstance().setDelega te(object : TaskExecutor() { override

    fun executeOnDiskIO(runnable: Runnable) { runnable.run() } override fun isMainThread(): Boolean { return true } override fun postToMainThread(runnable: Runnable) { runnable.run() } }) } 4QFL&YUFOUJPOLUΛ ࡞੒
  70. -JWF%BUB4QFL class TodoFeature : Spek({ useLiveData() Feature("Todo") { } })

    3PPUͷϥϜμ಺Ͱ ݺͼग़͠
  71. -JWF%BUB4QFL class TodoListViewModelSpec : Spek({ useLiveData() val application: Application by

    lazy { Mockito.mock(Application::class.java) } val todoListViewModel: TodoListViewModel by lazy { TodoListViewModel( application, Schedulers.trampoline() ) } val observer = mock<Observer<String>>() lateinit var filterWord: String Feature("TodoViewModel") { Scenario("TodoͷҰཡϑΟϧλʔ͢ΔͱLiveDataʹ৽͍͠஋͕ೖΔ") { Given("LiveData͕ΞΫςΟϒʹͳΔ") { todoListViewModel.wordLiveData.observeForever(observer) } When("ViewModelͷϑΟϧλʔϝιουΛ࣮ߦ͢Δ") { filterWord = "Spek" todoListViewModel.filter(filterWord) } Then("LiveDataͷvalue͕SpekʹͳΔ") { Mockito.verify(observer).onChanged(filterWord) } } } }) 7JFX.PEFMͷ࣋ͭ -JWF%BUBͷ஋͕ มߋ͞Ε͔ͨΛݟΔςετ
  72. -JWF%BUB4QFL val observer = mock<Observer<String>>() lateinit var filterWord: String Feature("TodoViewModel")

    { Scenario("TodoͷҰཡϑΟϧλʔ͢ΔͱLiveDataʹ৽͍͠஋͕ೖΔ") { Given("LiveData͕ΞΫςΟϒʹͳΔ") { todoListViewModel.wordLiveData.observeForever(observer) } When("ViewModelͷϑΟϧλʔϝιουΛ࣮ߦ͢Δ") { filterWord = "Spek" todoListViewModel.filter(filterWord) } Then("LiveDataͷvalue͕SpekʹͳΔ") { Mockito.verify(observer).onChanged(filterWord) } } } 0CTFSWFSͷ ϞοΫ࡞੒
  73. -JWF%BUB4QFL val observer = mock<Observer<String>>() lateinit var filterWord: String Feature("TodoViewModel")

    { Scenario("TodoͷҰཡϑΟϧλʔ͢ΔͱLiveDataʹ৽͍͠஋͕ೖΔ") { Given("LiveData͕ΞΫςΟϒʹͳΔ") { todoListViewModel.wordLiveData.observeForever(observer) } When("ViewModelͷϑΟϧλʔϝιουΛ࣮ߦ͢Δ") { filterWord = "Spek" todoListViewModel.filter(filterWord) } Then("LiveDataͷvalue͕SpekʹͳΔ") { Mockito.verify(observer).onChanged(filterWord) } } } 0CTFSWFΛ ։࢝͢Δ
  74. -JWF%BUB4QFL val observer = mock<Observer<String>>() lateinit var filterWord: String Feature("TodoViewModel")

    { Scenario("TodoͷҰཡϑΟϧλʔ͢ΔͱLiveDataʹ৽͍͠஋͕ೖΔ") { Given("LiveData͕ΞΫςΟϒʹͳΔ") { todoListViewModel.wordLiveData.observeForever(observer) } When("ViewModelͷϑΟϧλʔϝιουΛ࣮ߦ͢Δ") { filterWord = "Spek" todoListViewModel.filter(filterWord) } Then("LiveDataͷvalue͕SpekʹͳΔ") { Mockito.verify(observer).onChanged(filterWord) } } } 0CTFSWFSͷ PO$IBOHFE͕ ݺ͹Ε͔ͨνΣοΫ
  75. 3PPN3PCPMFDUSJD @RunWith(RobolectricTestRunner::class) @Config(sdk = [O_MR1]) class TodoDataBaseTest { private lateinit

    var database: TodoDatabase @Before fun openDatabase() { database = Room .inMemoryDatabaseBuilder( InstrumentationRegistry.getInstrumentation().targetContext, TodoDatabase::class.java ).allowMainThreadQueries() .build() } @After fun closeDatabase() { database.close() } @Test @Throws(Exception::class) fun insert() { assertThat(database.todoDao().count(), `is`(0)) val list = listOf( TodoEntity( name = "Robolectric࢖͏", category = 1 ), TodoEntity( name = "JUnit࢖͏", category = 1 ) ) database.todoDao().upsertAll(list) assertThat(database.todoDao().count(), `is`(2)) } }
  76. 3PPN3PCPMFDUSJD @Before fun openDatabase() { database = Room .inMemoryDatabaseBuilder( InstrumentationRegistry

    .getInstrumentation() .targetContext, TodoDatabase::class.java ).allowMainThreadQueries() .build() }
  77. 3PPN3PCPMFDUSJD @Before fun openDatabase() { database = Room .inMemoryDatabaseBuilder( InstrumentationRegistry

    .getInstrumentation() .targetContext, TodoDatabase::class.java ).allowMainThreadQueries() .build() } ίϯςΩετ͕ ͔ͭ͑Δ
  78. 3PPN3PCPMFDUSJD @Before fun openDatabase() { database = Room .inMemoryDatabaseBuilder( InstrumentationRegistry

    .getInstrumentation() .targetContext, TodoDatabase::class.java ).allowMainThreadQueries() .build() }
  79. 3PPN4QFL 5FTUPOZPVSIPTUNBDIJOF 3PPNVTFTUIF42-JUF4VQQPSU-JCSBSZ XIJDIQSPWJEFT JOUFSGBDFTUIBUNBUDIUIPTFJOUIF"OESPJE'SBNFXPSLDMBTTFT 5IJTTVQQPSUBMMPXTZPVUPQBTTDVTUPNJNQMFNFOUBUJPOTPG UIFTVQQPSUMJCSBSZUPUFTUZPVSEBUBCBTFRVFSJFT

  80. 3PPN4QFL 5FTUPOZPVSIPTUNBDIJOF 3PPNVTFTUIF42-JUF4VQQPSU-JCSBSZ XIJDIQSPWJEFT JOUFSGBDFTUIBUNBUDIUIPTFJOUIF"OESPJE'SBNFXPSLDMBTTFT 5IJTTVQQPSUBMMPXTZPVUPQBTTDVTUPNJNQMFNFOUBUJPOTPG UIFTVQQPSUMJCSBSZUPUFTUZPVSEBUBCBTFRVFSJFT ˒/PUF&WFOUIPVHIUIJTTFUVQBMMPXTZPVSUFTUTUPSVOWFSZ RVJDLMZ JUJTOUSFDPNNFOEFECFDBVTFUIFWFSTJPOPG42-JUF

    SVOOJOHPOZPVSEFWJDFŠBOEZPVSVTFSTEFWJDFTŠNJHIUOPU NBUDIUIFWFSTJPOPOZPVSIPTUNBDIJOF
  81. 3PPN4QFL class TodoDaoSpec : Spek({ useLiveData() val context: Context by

    lazy { Mockito.mock(Context::class.java) } val todoDatabase: TodoDatabase by lazy { Room.inMemoryDatabaseBuilder( context, TodoDatabase::class.java ).allowMainThreadQueries() .openHelperFactory(JdbcSQLiteOpenHelperFactory()) .build() } Feature("TodoDao") { lateinit var result: Single<Int> Scenario("TodoDatabase") { Given("two todos have already been registered") { val todoList = listOf( TodoEntity(name = "SpekͰUnitTestΛॻ͘", finished = false, deadline = 1L), TodoEntity(name = "JUnitͰUnitTestΛॻ͘", finished = false, deadline = 1L) ) todoDatabase.todoDao().upsertAll(todoList) } When("count todo") { result = todoDatabase.todoDao().count() } Then("it should be 2") { result.test().await().assertValue(2) } } } })
  82. 3PPN4QFL useLiveData() val context: Context by lazy { Mockito.mock(Context::class.java) }

    val todoDatabase: TodoDatabase by lazy { Room.inMemoryDatabaseBuilder( context, TodoDatabase::class.java ).allowMainThreadQueries() .openHelperFactory(JdbcSQLiteOpenHelperFactory()) .build() }
  83. 3PPN4QFL useLiveData() val context: Context by lazy { Mockito.mock(Context::class.java) }

    val todoDatabase: TodoDatabase by lazy { Room.inMemoryDatabaseBuilder( context, TodoDatabase::class.java ).allowMainThreadQueries() .openHelperFactory(JdbcSQLiteOpenHelperFactory()) .build() } +%#$ͷϔϧύʔ Λࢦఆ͢Δ
  84. 3PPN4QFL useLiveData() val context: Context by lazy { Mockito.mock(Context::class.java) }

    val todoDatabase: TodoDatabase by lazy { Room.inMemoryDatabaseBuilder( context, TodoDatabase::class.java ).allowMainThreadQueries() .openHelperFactory(JdbcSQLiteOpenHelperFactory()) .build() } ϝΠϯεϨουͷ ֬ೝΛऔΔ
  85. 3PPN4QFL useLiveData() val context: Context by lazy { Mockito.mock(Context::class.java) }

    val todoDatabase: TodoDatabase by lazy { Room.inMemoryDatabaseBuilder( context, TodoDatabase::class.java ).allowMainThreadQueries() .openHelperFactory(JdbcSQLiteOpenHelperFactory()) .build() }
  86. 3PPN4QFL useLiveData() val context: Context by lazy { Mockito.mock(Context::class.java) }

    val todoDatabase: TodoDatabase by lazy { Room.inMemoryDatabaseBuilder( context, TodoDatabase::class.java ).allowMainThreadQueries() .openHelperFactory(JdbcSQLiteOpenHelperFactory()) .build() } ίϯςΩετ͸ ୅༻Λ༻ҙ
  87. 3PPN4QFL Scenario("TodoDatabase") { lateinit var result: Single<Int> Given("two todos have

    already been registered") { val todoList = listOf( TodoEntity(name = "SpekͰUnitTestΛॻ͘", complete = false, deadline = 1L), TodoEntity(name = "JUnitͰUnitTestΛॻ͘", complete = false, deadline = 1L) ) todoDatabase.todoDao().upsertAll(todoList) } When("count todo") { result = todoDatabase.todoDao().count() } Then("it should be 2") { result.test().await().assertValue(2) } } ͍͖ͳΓͷ3Y
  88. ·ͱΊ ɾ4QFL͸+FU#SBJOTࣾ੡ͷςετϑϨʔϜϫʔΫ ɾ+6OJUʹൺ΂ͯه๏͕ಠಛ͕ͩɺΑΓࢿ࢈ʹͳΔςετ͕ॻ͚Δ ɾ࣮ߦॱংΛؾʹ্͔ͤͣΒॻ͜͏ ɾ3PPN΍-JWF%BUBΛ࢖͍ͬͯͯ΋"OESPJEϑϨʔϜϫʔΫ෦෼Λ޻ ෉͢Δͱ6OJU5FTU͸ॻ͚Δ

  89. ͋Γ͕ͱ͏͍͟͝·ͨ͠ʂ