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

ReactorKit Testability

Avatar for USAMI Kosuke USAMI Kosuke
February 15, 2019

ReactorKit Testability

Avatar for USAMI Kosuke

USAMI Kosuke

February 15, 2019
Tweet

More Decks by USAMI Kosuke

Other Decks in Programming

Transcript

  1. Design Goal • Testability : View ͱϩδοΫͷ෼཭ • Start Small

    : ΞϓϦͷҰ෦͚ͩͰ΋ద༻Ͱ͖Δ • Less Typing : ίʔυΛෳࡶʹ͠ͳ͍
  2. View ͱ Reactor • View ͷ੹຿ (1) • UI ૢ࡞

    → Action ͱͯ͠ Reactor ʹ౉͢ • Reactor ͷ੹຿ • Action → ॲཧΛߦ͍ State Λੜ੒͢Δ • View ͷ੹຿ (2) • State → UI ʹදࣔ͢Δ
  3. ੹຿ͷ෼཭ • UIViewController ʹ͸ View ͷ੹຿͚ͩΛ࣋ͨͤΔ • Reactor ͸ผΦϒδΣΫτͱͯ͠෼཭ʢͳ͓ɺReactor ͸

    UIKit ͸࢖Θͳ͍ʣ • ͜ΕʹΑΓ Testability ͕޲্͢Δ • ࠓճ͸ಛʹ View ͷ Testability ΛݟͯΈΔ
  4. View ϓϩτίϧ class MyViewController: View { func bind(reactor: MyReactor) {

    // ͜͜Ͱ Reactor ͱͷόΠϯσΟϯάΛߦ͏ // RxSwift Λ׆༻ } }
  5. Reactor ϓϩτίϧ class MyReactor: Reactor { enum Action { case

    myAction case myActionWithArg(Int) } struct State { var myValue1 = "" var myValue2 = false } }
  6. View ͷόΠϯσΟϯά : Action func bind(reactor: MyReactor) { myButton.rx.tap .map

    { Reactor.Action.myAction } .bind(to: reactor.action) .disposed(by: self.disposeBag) ʢͳ͓ɺreactor.action ͸ ActionSubjectʣ
  7. View ͷόΠϯσΟϯά : State func bind(reactor: MyReactor) { reactor.state .map

    { $0.myValue1 } .bind(to: myLabel.rx.text) .disposed(by: self.disposeBag) ʢͳ͓ɺreactor.state ͸ Observableʣ
  8. Reactor ͷॲཧ : mutate() • Action Λड͚औͬͯ Observable<Mutation> Λฦ͢ •

    ۩ମతͳॲཧʢWeb API ࣮ߦɺσʔλϕʔεΞΫηεɺͳͲʣ Λߦ͏ Observable Λੜ੒͢Δ • ࣮ࡍʹॲཧΛߦ͏͔Ͳ͏͔ͷ൑அͳͲ͸ Reactor ͷ໾໨ • ͜ΕʹΑΓɺView ଆͰ͸ Action Λੜ੒͢Δ͔Ͳ͏͔Λ൑ அ͠ͳ͍ͨΊɺView ͷ࣮૷͕όΠϯσΟϯά͚ͩͰ͢Ή
  9. Reactor ͷॲཧ : reduce() • Mutation ͱલͷ State Λड͚औͬͯ State

    Λฦ͢ • ॲཧͷ݁Ռͱલͷঢ়ଶΛߟྀͯ࣍͠ͷঢ়ଶΛܾΊΔͷ͕໾໨ • ͜ΕʹΑΓɺView ଆͰ͸લͷঢ়ଶΛߟྀ͢Δͱ͍ͬͨॲཧ͕ ෆཁʹͳΔͨΊɺView ͷ࣮૷͕όΠϯσΟϯά͚ͩͰ͢Ή
  10. View ͷςετ : Action • ίʔυͰ UI ૢ࡞Λൃੜͤ͞Δ • myButton.sendActions(for

    .touchUpInside) • ͦͷ݁Ռͱͯ͠ɺReactor ʹ Action ΦϒδΣΫτ͕౉͞Ε ͨ͜ͱΛ֬ೝ͍ͨ͠ • Ͳ͏΍ͬͯʁ ʹ Reactor ͷελϒΛ༻ҙ͢Ε͹͍͍ • ࣮͸ ReactorKit Ͱ͸ελϒ͕͢Ͱʹ༻ҙ͞Ε͍ͯΔ
  11. View ͷςετ : Action func testMyAction() { let reactor =

    MyReactor() reactor.stub.isEnabled = true let view = MyView() view.reactor = reactor view.myButton.sendActions(for .touchUpInside) XCTAssertEqual(reactor.stub.actions.last, .myAction) }
  12. View ͷςετ : State • ΍͸Γ Reactor ͷελϒΛ׆༻͢Δ • ίʔυͰ

    Reactor ͷ State มԽΛى͜͢ • ͦͷ݁Ռͱͯ͠ɺUI ද͕ࣔมߋ͞Εͨ͜ͱΛ֬ೝ͢Δ
  13. View ͷςετ : State func testMyAction() { let reactor =

    MyReactor() reactor.stub.isEnabled = true let view = MyView() view.reactor = reactor reactor.stub.state.value = MyReactor.State(myValue1: "abc") XCTAssertEqual(view.myLabel.text, "abc") }
  14. View ͷςετ·ͱΊ • Կ͕ςετͰ͖ͨͷ͔ʁ : View ͕੹຿ΛՌ͍ͨͯ͠Δ͜ͱ • View ͷ࣮૷ͱͯ͠͸όΠϯσΟϯά͕ͪΌΜͱͰ͖͍ͯΔ͜

    ͱ • ͦ΋ͦ΋ςετඞཁʁ : Testability ޲্ͷͨΊγϯϓϧ ͳΦϒδΣΫτʹͳͬͨ݁Ռɺ୯७͗ͯ͢ςετෆཁͰ͸ͱ͍ ͏Ϩϕϧʹ • ࣮ࡍʹςετίʔυΛॻ͔͘Ͳ͏͔͸έʔεόΠέʔε
  15. Reactor ͷ୯ମςετʢུ֓ʣ • ʮͦͷΦϒδΣΫτͷ੹຿ΛՌ͍ͨͯ͠Δ͔ʯΛςετ͢Δ • Reactor ͷ੹຿ : Action →

    State • ίʔυͰ Action Λൃੜͤͯ͞ɺState มߋΛ֬ೝ͢Δ • Reactor ͸ View ΁ͷґଘ͕ͳ͍ͨΊɺಠཱͯ͠ςετՄೳ
  16. Reactor ͷ୯ମςετʢུ֓ʣ • Reactor ͷதͰ Web API ࣮ߦɺσʔλϕʔεΞΫηεɺͳ Ͳ͕͋Δͱ୯ମςετ͠ʹ͘͘ͳΔ •

    ͦ͜ͰɺͦΕΒΛ Service ͱͯ͠ Reactor ͷ֎ʹ੾Γग़͢ • Service ΛελϒԽ͢Δ͜ͱͰ Reactor ͕୯ମςετՄೳ
  17. ·ͱΊ • ෳ਺ͷ੹຿Λ͕࣋ͪͪͳ UIViewController ʹ͍ͭͯɺ ReactorKit Ͱ View ͱ Reactor

    ʹ੹຿Λ෼཭ͨ͠ • ͜ΕʹΑΓɺView ΍ Reactor ͕ςετՄೳʹͳͬͨ