droidkaigi-2016

836437265cbba12ee1b24bbb359a6c15?s=47 Yuya Kaido
February 18, 2016

 droidkaigi-2016

836437265cbba12ee1b24bbb359a6c15?s=128

Yuya Kaido

February 18, 2016
Tweet

Transcript

  1. ๻͕ςετॻ͚ॻ͚ ͓͡͞ΜʹͳͬͨܦҢͱ ͦͷաఔͰ΍ͬͨ͜ͱ DroidKaigi 2016 yuyakaido

  2. ࣗݾ঺հ • ւ౻༏໻ʢ͔͍Ͳ͏Ώ͏΍ʣ • גࣜձࣾΤ΢ϨΧ • ςετॻ͚ॻ͚͓͡͞Μʢ৽ଔʣ • Android͸2೥ 

    yuyakaido yuyakaido
  3. גࣜձࣾΤ΢ϨΧ • ࣗࣾαʔϏεͷاըɾ։ൃɾӡӦ • ΦϯϥΠϯσʔςΟϯάαʔϏεɿ • Χοϓϧઐ༻ΞϓϦɿ • ࣾһ਺ɿ85໊ •

    IACάϧʔϓ  ΤϯδχΞ 55 ඇΤϯδχΞ 30
  4. Android൛Λ୲౰ ↓

  5. Couples 

  6. ֓ཁ • ೲظΛ༏ઌ͢Δ͋·Γઃܭ͕ૄ͔ʹ • ౰વςετΛॻ͘ՋͳΜͯͳ͍ • ޙ͔ΒςετΛॻ͜͏ͱࢥͬͯ΋ॻ͚ͳ͍ • ςελϒϧͳઃܭʹ͢ΔͨΊʹԿΛ΍͔ͬͨ 

  7. ໨࣍ • ςετ͕ͳ͍ͱͲ͏ਏ͍ͷ͔ • Couplesͷઃܭ • ςελϏϦςΟͷߴ͍ઃܭ • ςετख๏ɾϑϨʔϜϫʔΫ •

    αϯϓϧΞϓϦͰͷςετ • ςετΛॻ͘จԽΛ࡞ΔͨΊʹ • ·ͱΊ 
  8. ໨࣍ • ςετ͕ͳ͍ͱͲ͏ਏ͍ͷ͔ • Couplesͷઃܭ • ςελϏϦςΟͷߴ͍ઃܭ • ςετख๏ɾϑϨʔϜϫʔΫ •

    αϯϓϧΞϓϦͰͷςετ • ςετΛॻ͘จԽΛ࡞ΔͨΊʹ • ·ͱΊ 
  9. CouplesͰͷྫ • ๲େͳςετέʔεͷਓྗ֬ೝ • ӨڹൣғͷߟྀϛεʹΑΔόά • ςετέʔεͷෳࡶԽ 

  10. ๲େͳςετέʔεͷਓྗ֬ೝ • Couples͸݁ߏػೳ͕ଟ͍ • 50ϖʔδҎ্ͷGoogle Spreadsheet • ϦϦʔεલʹӨڹͷ͋ΔςετέʔεΛਓྗͰ શ෦֬ೝ 

  11.  ςετ߲໨ ػೳ ը໘ ୺຤ ݁Ռ ͭΒ͍ʂʂ

  12. ๲େͳςετέʔεͷਓྗ֬ೝ • ਓྗͰͳ͍ͱෆՄೳͳςετ΋͔֬ʹ͋Δ • Ͱ΋ɺࣗಈςετग़དྷͦ͏ͳ෦෼΋݁ߏ͋Δ 

  13. ͦͷଞը໘ • ϓϩϑΟʔϧʹભҠ͢Δ͜ͱ • ͓ؾʹೖΓʹભҠ͢Δ͜ͱ • ώετϦʔʹભҠ͢Δ͜ͱ • etc… 

    ࣗಈԽग़དྷΔͰ͠ΐɺɺ
  14. ӨڹൣғͷߟྀϛεʹΑΔόά • iOSͷϦϦʔεޙʹAndroidʹணखͨͨ͠Ίɺ ౰࣌͸ૣ͘ϦϦʔε͢Δ͜ͱΛॏࢹ • ഁ୼ͨ͠ج൫ઃܭͱίϐϖͷཛྷͷ͍ͤͰશવ ؔ܎ͳ͍Օॴ͕όάΔ • ϦϦʔεલʹશͯͷςετέʔεΛ໢ཏ͢Δͷ ͸ݱ࣮త͡Όͳ͍

    
  15. ςετέʔεͷෳࡶԽ • ςετέʔεʹґଘؔ܎͕ൃੜ࢝͠ΊΔ • ͜ͷςετ͕ඞཁͳ৔߹͸͜ͷςετ΋΍Β ͳ͚Ε͹͍͚ͳ͍తͳ 

  16. ͦΕͧΕͷ໰୊఺ • ๲େͳςετέʔεͷਓྗ֬ೝ • ਓతϦιʔεͷ࿘අ → ػձଛࣦ • ӨڹൣғͷߟྀϛεʹΑΔόά •

    Ϣʔβʔͷ཭୤ → ػձଛࣦ • ςετέʔεͷෳࡶԽ • ਓతϦιʔεͷ࿘අ → ػձଛࣦ 
  17. ͓͡͞Μ͸͜͏ߟ͑ͨ 

  18. • ͜ͷ··͡Όεέʔϧ͠ͳ͍ • ͦΕͲ͜Ζ͔ϝϯςग़དྷͳ͘ͳΔ • Ͱ΋ɺ·ͩؒʹ߹͏͸ͣɺɺ 

  19. Α͠ɺςετΛॻ͜͏ 

  20. ςετํ਑ • UI͸සൟʹมߋ͕͋ΔͨΊίετʹݟ߹Θͳ͍Մೳੑ͕͋Δ • ·ͣ͸มߋͷগͳ͍όοΫΤϯυ͔Β߈ΊΑ͏ • όοΫΤϯυ • ͋͘·ͰAndroidΞϓϦ಺ͰͷόοΫΤϯυ •

    DB΍APIΞΫηε 
  21. ɾɾɾɾɾ 

  22. ςετ͕ॻ͚ͳ͍ɾɾɾ 

  23. ໨࣍ • ςετ͕ͳ͍ͱͲ͏ਏ͍ͷ͔ • Couplesͷઃܭ • ςελϏϦςΟͷߴ͍ઃܭ • ςετख๏ɾϑϨʔϜϫʔΫ •

    αϯϓϧΞϓϦͰͷςετ • ςετΛॻ͘จԽΛ࡞ΔͨΊʹ • ·ͱΊ 
  24. ݱঢ়ͷઃܭ  View Activity/Fragment Model Request DB Server

  25. ݱঢ়ͷઃܭ • ϚονϣͳActivity/Fragment • ຊ౰ʹͼͬ͘Γ͢Δ͘Β͍Ϛονϣ • ςετ͕ॻ͚ͳ͍Ͳ͜Ζ͔ػೳ௥Ճ΋ਏ͍ • όοΫΤϯυͷΫϥεؒͷґଘؔ܎͕ෳࡶ •

    ςετ͕ॻ͖ʹ͍͘ • ϞοΫαʔόʔ΁ͷࠩ͠ସ͕͑೉͍͠ 
  26. ͓͡͞Μͷબ୒ࢶ • طଘͷόοΫΤϯυʹ௚઀खΛೖΕΔ • ৽͍͠όοΫΤϯυΛ࡞ͬͯ৐Γ׵͑ 

  27. ͓͡͞Μͷܾஅ • طଘͷόοΫΤϯυʹ௚઀खΛೖΕΔ • ґଘؔ܎͕ෳࡶ • ςετ͕ͳ͍ঢ়ଶͰखΛೖΕΔͷ͕ා͍ • ৽͍͠όοΫΤϯυΛ࡞ͬͯ৐Γ׵͑ •

    ґଘؔ܎Λ៉ྷʹ੔ཧ • ςετΛॻ͖ͳ͕Βػೳ୯ҐͰॱ࣍ஔ͖׵͑Δ͜ͱ ͰϦεΫΛԼ͛Δ 
  28. ໨࣍ • ςετ͕ͳ͍ͱͲ͏ਏ͍ͷ͔ • Couplesͷઃܭ • ςελϏϦςΟͷߴ͍ઃܭ • ςετख๏ɾϑϨʔϜϫʔΫ •

    αϯϓϧΞϓϦͰͷςετ • ςετΛॻ͘จԽΛ࡞ΔͨΊʹ • ·ͱΊ 
  29. ςελϏϦςΟΛߴΊΔͨΊʹ͸ • ֤૚ͷ໾ׂ͕໌֬ • ద੾ͳϞδϡʔϧԽ • CIαʔόʔͰܧଓతͳςετ͕Մೳ 

  30. ৽͍͠ઃܭ  View Activity/Fragment Repository Database Network DB Server Model

    ϑϩϯτΤϯυ όοΫΤϯυ
  31. όοΫΤϯυ  Repository Database Network DB Server ActiveAndroid Retrofit ×

    OkHttp Observable<T> Observable<T>
  32. όοΫΤϯυ • ֤૚ͷ໾ׂ͕໌֬ʹ • CIαʔόʔ্ͰܧଓతʹςετՄೳʹ 

  33. ϑϩϯτΤϯυ • ݱࡏ͸MVC • ݱࡏํ਑Λݕ౼த • MVC • MVP •

    etc… 
  34. MVC  Model View Controller Activity/Fragment UIΠϕϯτ ߋ৽ Ϟσϧૢ࡞ ߋ৽σʔλ

    جຊతʹ͸௚઀ࢀর͠ͳ͍
  35. MVC • ϝϦοτ • ҰൠతͳΞʔΩςΫνϟͰ޿͘஌ΒΕ͍ͯΔ • σϝϦοτ • Activity/Fragment͕ViewͱControllerͷੑ࣭ Λ΋͍ͬͯΔͨΊɺϚονϣʹͳΓ͕ͪ

    
  36. MVP  Model View Presenter Activity/Fragment UIΠϕϯτ ߋ৽ Ϟσϧૢ࡞ ߋ৽σʔλ

    جຊతʹ͸௚઀ࢀর͠ͳ͍
  37. MVP • ϝϦοτ • ੹຿ͷ෼཭ • Activity/Fragment = View •

    Presenter = Controller • σϝϦοτ • Ϋϥε਺͕ଟ͘ͳΔ • νʔϜ։ൃͷ৔߹͸͋Δఔ౓υΩϡϝϯτ͕ඞཁ 
  38. ϑϩϯτΤϯυ • ৭ʑͳΞʔΩςΫνϟ͕ଘࡏ͢Δ͕ɺ·ͩࣗ ෼ͷதͰෲམͪͰ͖͍ͯͳ͍ • ݁ہ͸ςετΛॻ͘͜ͱ͕໨తͳͷͰɺಛఆ ͷΞʔΩςΫνϟʹͩ͜ΘΔ΂͖͡Όͳ͍ • όοΫΤϯυΛ៉ྷʹͨ͜͠ͱͰɺϑϩϯτ ΋͋Δఔ౓៉ྷʹͳͬͨͷͰɺςετ͕ॻ͚

    ͦ͏ 
  39. ໨࣍ • ςετ͕ͳ͍ͱͲ͏ਏ͍ͷ͔ • Couplesͷઃܭ • ςελϏϦςΟͷߴ͍ઃܭ • ςετख๏ɾϑϨʔϜϫʔΫ •

    αϯϓϧΞϓϦͰͷςετ • ςετΛॻ͘จԽΛ࡞ΔͨΊʹ • ·ͱΊ 
  40. ςετख๏ • Ϣχοτςετ • ϝιου୯ҐͰϩδοΫͷଥ౰ੑΛςετ ͢Δ͜ͱ • UIςετ • UIͷಈ͖΋ؚΊͨςετΛ͢Δ͜ͱ

    
  41. ςετϑϨʔϜϫʔΫ • ϩδοΫςετ • JUnit4 • UIςετ • Espresso •

    Robolectric 
  42. JUnit4 • Testing Support Library • ϢχοτςετͷͨΊͷϑϨʔϜϫʔΫ • ϩδοΫͷςετ͚ͩͳΒ͜Ε͚ͩͰे෼ 

  43. Espresso • Testing Support Library • UIͷಈ͖΋ؚΊͨςετ͕ॻ͚Δ • ࣮ػ্Ͱςετ࣮ߦ •

    ਓ͕ؒૢ࡞͢Δͷͱಉ༷ͷ͕͔͔࣌ؒΔ 
  44. Espresso 

  45. Robolectric • UIͷಈ͖ΛؚΊͨςετ͕ॻ͚Δ • ࣮ػΛඞཁͱ͠ͳ͍ • ެࣜͰ͸API21·Ͱ͔͠αϙʔτ͍ͯ͠ͳ͍ ͕ɺAPI23Ͱ΋࢖͑Δ 

  46. ໨࣍ • ςετ͕ͳ͍ͱͲ͏ਏ͍ͷ͔ • Couplesͷઃܭ • ςελϏϦςΟͷߴ͍ઃܭ • ςετख๏ɾϑϨʔϜϫʔΫ •

    αϯϓϧΞϓϦͰͷςετ • ςετΛॻ͘จԽΛ࡞ΔͨΊʹ • ·ͱΊ 
  47. αϯϓϧ࣮૷ • konifar/droidkaigi2016ͷContributorsΛදࣔ • yuyakaido/android-genesis 

  48. Contributor @Table
 public class Contributor {
 
 @Column(unique = true,

    uniqueOnConflict = OnConflict.REPLACE)
 @SerializedName("login")
 public String login;
 
 @Column
 @Nullable
 @SerializedName("avatar_url")
 public String avatarUrl;
 
 @Column
 @Nullable
 @SerializedName("html_url")
 public String htmlUrl;
 
 @Column
 @SerializedName("contributions")
 public int contributions;
 
 } 
  49. GithubDatabase public static Observable<List<Contributor>> getContributors() {
 return Database.getDatabase()
 .selectFromContributor()
 .executeAsObservable()


    .toList();
 } 
  50. GithubNetwork public String getBaseUrl() {
 return "https://api.github.com";
 }
 
 public

    Observable<List<Contributor>> getContributors(String owner, String repo) {
 GithubApi githubApi = ApiClientGenerater.generate(GithubApi.class, getBaseUrl());
 return githubApi.getContributors(owner, repo)
 .map(new Func1<List<Contributor>, List<Contributor>>() {
 @Override
 public List<Contributor> call(List<Contributor> contributors) {
 Database.getDatabase()
 .prepareInsertIntoContributor()
 .executeAll(contributors);
 return contributors;
 }
 });
 }
 
 public Observable<List<Contributor>> getContributors() {
 return getContributors("konifar", "droidkaigi2016");
 } 
  51. GithubNetwork public String getBaseUrl() {
 return "https://api.github.com";
 }
 
 public

    Observable<List<Contributor>> getContributors(String owner, String repo) {
 GithubApi githubApi = ApiClientGenerater.generate(GithubApi.class, getBaseUrl());
 return githubApi.getContributors(owner, repo)
 .map(new Func1<List<Contributor>, List<Contributor>>() {
 @Override
 public List<Contributor> call(List<Contributor> contributors) {
 Database.getDatabase()
 .prepareInsertIntoContributor()
 .executeAll(contributors);
 return contributors;
 }
 });
 }
 
 public Observable<List<Contributor>> getContributors() {
 return getContributors("konifar", "droidkaigi2016");
 } 
  52. GithubNetwork public String getBaseUrl() {
 return "https://api.github.com";
 }
 
 public

    Observable<List<Contributor>> getContributors(String owner, String repo) {
 GithubApi githubApi = ApiClientGenerater.generate(GithubApi.class, getBaseUrl());
 return githubApi.getContributors(owner, repo)
 .map(new Func1<List<Contributor>, List<Contributor>>() {
 @Override
 public List<Contributor> call(List<Contributor> contributors) {
 Database.getDatabase()
 .prepareInsertIntoContributor()
 .executeAll(contributors);
 return contributors;
 }
 });
 }
 
 public Observable<List<Contributor>> getContributors() {
 return getContributors("konifar", "droidkaigi2016");
 } 
  53. GithubNetwork public String getBaseUrl() {
 return "https://api.github.com";
 }
 
 public

    Observable<List<Contributor>> getContributors(String owner, String repo) {
 GithubApi githubApi = ApiClientGenerater.generate(GithubApi.class, getBaseUrl());
 return githubApi.getContributors(owner, repo)
 .map(new Func1<List<Contributor>, List<Contributor>>() {
 @Override
 public List<Contributor> call(List<Contributor> contributors) {
 Database.getDatabase()
 .prepareInsertIntoContributor()
 .executeAll(contributors);
 return contributors;
 }
 });
 }
 
 public Observable<List<Contributor>> getContributors() {
 return getContributors("konifar", "droidkaigi2016");
 } 
  54. GithubNetwork public String getBaseUrl() {
 return "https://api.github.com";
 }
 
 public

    Observable<List<Contributor>> getContributors(String owner, String repo) {
 GithubApi githubApi = ApiClientGenerater.generate(GithubApi.class, getBaseUrl());
 return githubApi.getContributors(owner, repo)
 .map(new Func1<List<Contributor>, List<Contributor>>() {
 @Override
 public List<Contributor> call(List<Contributor> contributors) {
 Database.getDatabase()
 .prepareInsertIntoContributor()
 .executeAll(contributors);
 return contributors;
 }
 });
 }
 
 public Observable<List<Contributor>> getContributors() {
 return getContributors("konifar", "droidkaigi2016");
 } 
  55. GithubNetwork public String getBaseUrl() {
 return "https://api.github.com";
 }
 
 public

    Observable<List<Contributor>> getContributors(String owner, String repo) {
 GithubApi githubApi = ApiClientGenerater.generate(GithubApi.class, getBaseUrl());
 return githubApi.getContributors(owner, repo)
 .map(new Func1<List<Contributor>, List<Contributor>>() {
 @Override
 public List<Contributor> call(List<Contributor> contributors) {
 Database.getDatabase()
 .prepareInsertIntoContributor()
 .executeAll(contributors);
 return contributors;
 }
 });
 }
 
 public Observable<List<Contributor>> getContributors() {
 return getContributors("konifar", "droidkaigi2016");
 } 
  56. GithubNetwork public String getBaseUrl() {
 return "https://api.github.com";
 }
 
 public

    Observable<List<Contributor>> getContributors(String owner, String repo) {
 GithubApi githubApi = ApiClientGenerater.generate(GithubApi.class, getBaseUrl());
 return githubApi.getContributors(owner, repo)
 .map(new Func1<List<Contributor>, List<Contributor>>() {
 @Override
 public List<Contributor> call(List<Contributor> contributors) {
 Database.getDatabase()
 .prepareInsertIntoContributor()
 .executeAll(contributors);
 return contributors;
 }
 });
 }
 
 public Observable<List<Contributor>> getContributors() {
 return getContributors("konifar", "droidkaigi2016");
 } 
  57. GithubDatabaseͷςετ final int COUNT = 10;
 List<Contributor> contributors = new

    ArrayList<>(COUNT);
 for (int i = 0; i < COUNT; i++) {
 Contributor contributor = new Contributor();
 contributor.login = String.valueOf(i);
 contributor.avatarUrl = String.valueOf(i);
 contributor.htmlUrl = String.valueOf(i);
 contributor.contributions = i;
 contributors.add(contributor);
 }
 
 Database.getDatabase()
 .prepareInsertIntoContributor()
 .executeAll(contributors);
 
 TestSubscriber<List<Contributor>> testSubscriber = new TestSubscriber<>();
 GithubDatabase.getContributors().subscribe(testSubscriber);
 
 testSubscriber.assertNoErrors();
 testSubscriber.assertCompleted();
 List<Contributor> result = testSubscriber.getOnNextEvents().get(0);
 assertThat(result.size(), is(contributors.size())); 
  58. GithubDatabaseͷςετ final int COUNT = 10;
 List<Contributor> contributors = new

    ArrayList<>(COUNT);
 for (int i = 0; i < COUNT; i++) {
 Contributor contributor = new Contributor();
 contributor.login = String.valueOf(i);
 contributor.avatarUrl = String.valueOf(i);
 contributor.htmlUrl = String.valueOf(i);
 contributor.contributions = i;
 contributors.add(contributor);
 }
 
 Database.getDatabase()
 .prepareInsertIntoContributor()
 .executeAll(contributors);
 
 TestSubscriber<List<Contributor>> testSubscriber = new TestSubscriber<>();
 GithubDatabase.getContributors().subscribe(testSubscriber);
 
 testSubscriber.assertNoErrors();
 testSubscriber.assertCompleted();
 List<Contributor> result = testSubscriber.getOnNextEvents().get(0);
 assertThat(result.size(), is(contributors.size())); 
  59. TestSubscriber • RxJavaͷςετ༻Ϋϥε • ΠϕϯτΛه࿥ͯ͘͠ΕΔศརͳ΍ͭ • onNext(), onError(), onCompleted()ͰassertΛ ॻ͍ͯ΋͍͍͚Ͳ΋ɺɺɺ

    
  60. TestSubscriber Integer[] integers = new Integer[] {1, 2, 3};
 Observable<Integer>

    observable = Observable.from(integers);
 
 observable.subscribe(new Subscriber<Integer>() {
 @Override
 public void onCompleted() {}
 
 @Override
 public void onError(Throwable e) {}
 
 @Override
 public void onNext(Integer integer) {
 throw new RuntimeException();
 }
 }); 
  61. TestSubscriber @Test
 public void subscriberTest() {
 Integer[] integers = new

    Integer[] {1, 2, 3};
 Observable<Integer> observable = Observable.from(integers);
 
 TestSubscriber<Integer> testSubscriber = new TestSubscriber<>();
 observable.subscribe(testSubscriber);
 
 testSubscriber.assertNoErrors();
 testSubscriber.assertValueCount(integers.length);
 testSubscriber.assertValues(integers);
 testSubscriber.assertCompleted();
 } 
  62. GithubDatabaseͷςετ final int COUNT = 10;
 List<Contributor> contributors = new

    ArrayList<>(COUNT);
 for (int i = 0; i < COUNT; i++) {
 Contributor contributor = new Contributor();
 contributor.login = String.valueOf(i);
 contributor.avatarUrl = String.valueOf(i);
 contributor.htmlUrl = String.valueOf(i);
 contributor.contributions = i;
 contributors.add(contributor);
 }
 
 Database.getDatabase()
 .prepareInsertIntoContributor()
 .executeAll(contributors);
 
 TestSubscriber<List<Contributor>> testSubscriber = new TestSubscriber<>();
 GithubDatabase.getContributors().subscribe(testSubscriber);
 
 testSubscriber.assertNoErrors();
 testSubscriber.assertCompleted();
 List<Contributor> result = testSubscriber.getOnNextEvents().get(0);
 assertThat(result.size(), is(contributors.size())); 
  63. GithubDatabaseͷςετ final int COUNT = 10;
 List<Contributor> contributors = new

    ArrayList<>(COUNT);
 for (int i = 0; i < COUNT; i++) {
 Contributor contributor = new Contributor();
 contributor.login = String.valueOf(i);
 contributor.avatarUrl = String.valueOf(i);
 contributor.htmlUrl = String.valueOf(i);
 contributor.contributions = i;
 contributors.add(contributor);
 }
 
 Database.getDatabase()
 .prepareInsertIntoContributor()
 .executeAll(contributors);
 
 TestSubscriber<List<Contributor>> testSubscriber = new TestSubscriber<>();
 GithubDatabase.getContributors().subscribe(testSubscriber);
 
 testSubscriber.assertNoErrors();
 testSubscriber.assertCompleted();
 List<Contributor> result = testSubscriber.getOnNextEvents().get(0);
 assertThat(result.size(), is(contributors.size())); 
  64. GithubDatabaseͷςετ final int COUNT = 10;
 List<Contributor> contributors = new

    ArrayList<>(COUNT);
 for (int i = 0; i < COUNT; i++) {
 Contributor contributor = new Contributor();
 contributor.login = String.valueOf(i);
 contributor.avatarUrl = String.valueOf(i);
 contributor.htmlUrl = String.valueOf(i);
 contributor.contributions = i;
 contributors.add(contributor);
 }
 
 Database.getDatabase()
 .prepareInsertIntoContributor()
 .executeAll(contributors);
 
 TestSubscriber<List<Contributor>> testSubscriber = new TestSubscriber<>();
 GithubDatabase.getContributors().subscribe(testSubscriber);
 
 testSubscriber.assertNoErrors();
 testSubscriber.assertCompleted();
 List<Contributor> result = testSubscriber.getOnNextEvents().get(0);
 assertThat(result.size(), is(contributors.size())); 
  65. GithubDatabaseͷςετ final int COUNT = 10;
 List<Contributor> contributors = new

    ArrayList<>(COUNT);
 for (int i = 0; i < COUNT; i++) {
 Contributor contributor = new Contributor();
 contributor.login = String.valueOf(i);
 contributor.avatarUrl = String.valueOf(i);
 contributor.htmlUrl = String.valueOf(i);
 contributor.contributions = i;
 contributors.add(contributor);
 }
 
 Database.getDatabase()
 .prepareInsertIntoContributor()
 .executeAll(contributors);
 
 TestSubscriber<List<Contributor>> testSubscriber = new TestSubscriber<>();
 GithubDatabase.getContributors().subscribe(testSubscriber);
 
 testSubscriber.assertNoErrors();
 testSubscriber.assertCompleted();
 List<Contributor> result = testSubscriber.getOnNextEvents().get(0);
 assertThat(result.size(), is(contributors.size())); 
  66. GithubNetworkͷςετ File file = new File("src/test/assets/json/github_contributors.json");
 MockWebServer mockWebServer = new

    MockWebServer();
 mockWebServer.enqueue(ResponseUtil.createMockResponse(file));
 mockWebServer.start();
 
 GithubNetwork githubNetwork = GithubNetwork.getInstance();
 githubNetwork = spy(githubNetwork);
 when(githubNetwork.getBaseUrl())
 .thenReturn(mockWebServer.url("/").toString());
 
 TestSubscriber<List<Contributor>> testSubscriber = new TestSubscriber<>();
 githubNetwork.getContributors().subscribe(testSubscriber);
 
 testSubscriber.assertNoErrors();
 testSubscriber.assertCompleted();
 List<Contributor> contributors = testSubscriber.getOnNextEvents().get(0);
 assertThat(contributors.size(), is(1)); 
  67. GithubNetworkͷςετ File file = new File("src/test/assets/json/github_contributors.json");
 MockWebServer mockWebServer = new

    MockWebServer();
 mockWebServer.enqueue(ResponseUtil.createMockResponse(file));
 mockWebServer.start();
 
 GithubNetwork githubNetwork = GithubNetwork.getInstance();
 githubNetwork = spy(githubNetwork);
 when(githubNetwork.getBaseUrl())
 .thenReturn(mockWebServer.url("/").toString());
 
 TestSubscriber<List<Contributor>> testSubscriber = new TestSubscriber<>();
 githubNetwork.getContributors().subscribe(testSubscriber);
 
 testSubscriber.assertNoErrors();
 testSubscriber.assertCompleted();
 List<Contributor> contributors = testSubscriber.getOnNextEvents().get(0);
 assertThat(contributors.size(), is(1)); 
  68. MockWebServer • square/okhttp/mockwebserver • ໊લͷ௨ΓɺWebαʔόʔͷϞοΫ͕Մೳ • ৴པͷSquare੡ 

  69. MockWebServer File file = new File( "src/test/assets/json/github_contributors.json");
 MockWebServer mockWebServer =

    new MockWebServer();
 mockWebServer.enqueue(ResponseUtil.createMockResponse(file));
 mockWebServer.start(); 
  70. MockWebServer File file = new File( "src/test/assets/json/github_contributors.json");
 MockWebServer mockWebServer =

    new MockWebServer();
 mockWebServer.enqueue(ResponseUtil.createMockResponse(file));
 mockWebServer.start(); 
  71. MockWebServer File file = new File( "src/test/assets/json/github_contributors.json");
 MockWebServer mockWebServer =

    new MockWebServer();
 mockWebServer.enqueue(ResponseUtil.createMockResponse(file));
 mockWebServer.start(); 
  72. MockWebServer File file = new File( "src/test/assets/json/github_contributors.json");
 MockWebServer mockWebServer =

    new MockWebServer();
 mockWebServer.enqueue(ResponseUtil.createMockResponse(file));
 mockWebServer.start(); 
  73. Mockito • https://github.com/mockito/mockito • Ϣχοτςετ༻ͷϞοΫϥΠϒϥϦ • ϝιου͕ݺͼग़͞Εͨ͜ͱΛ֬ೝ • ϝιουͷฦ໭஋ΛϞοΫ 

  74. ϝιουͷݺͼग़֬͠ೝ // mock creation
 List mockedList = mock(List.class);
 
 //

    using mock object - it does not throw any "unexpected interaction" exception
 mockedList.add("one");
 mockedList.clear();
 
 // selective, explicit, highly readable verification
 verify(mockedList).add("one");
 verify(mockedList).clear(); 
  75. ϝιουͷݺͼग़֬͠ೝ // mock creation
 List mockedList = mock(List.class);
 
 //

    using mock object - it does not throw any "unexpected interaction" exception
 mockedList.add("one");
 mockedList.clear();
 
 // selective, explicit, highly readable verification
 verify(mockedList).add("one");
 verify(mockedList).clear(); 
  76. ϝιουͷݺͼग़֬͠ೝ // mock creation
 List mockedList = mock(List.class);
 
 //

    using mock object - it does not throw any "unexpected interaction" exception
 mockedList.add("one");
 mockedList.clear();
 
 // selective, explicit, highly readable verification
 verify(mockedList).add("one");
 verify(mockedList).clear(); 
  77. ϝιουͷݺͼग़֬͠ೝ // mock creation
 List mockedList = mock(List.class);
 
 //

    using mock object - it does not throw any "unexpected interaction" exception
 mockedList.add("one");
 mockedList.clear();
 
 // selective, explicit, highly readable verification
 verify(mockedList).add("one");
 verify(mockedList).clear(); 
  78. ϝιουͷฦ໭஋ͷϞοΫ // you can mock concrete classes, not only interfaces


    LinkedList mockedList = mock(LinkedList.class);
 
 // stubbing appears before the actual execution
 when(mockedList.get(0)).thenReturn("first");
 
 // the following is "first"
 assertThat((String) mockedList.get(0), is("first"));
 
 // the following is "null" because get(999) was not stubbed
 assertThat(mockedList.get(999), nullValue()); 
  79. ϝιουͷฦ໭஋ͷϞοΫ // you can mock concrete classes, not only interfaces


    LinkedList mockedList = mock(LinkedList.class);
 
 // stubbing appears before the actual execution
 when(mockedList.get(0)).thenReturn("first");
 
 // the following is "first"
 assertThat((String) mockedList.get(0), is("first"));
 
 // the following is "null" because get(999) was not stubbed
 assertThat(mockedList.get(999), nullValue()); 
  80. ϝιουͷฦ໭஋ͷϞοΫ // you can mock concrete classes, not only interfaces


    LinkedList mockedList = mock(LinkedList.class);
 
 // stubbing appears before the actual execution
 when(mockedList.get(0)).thenReturn("first");
 
 // the following is "first"
 assertThat((String) mockedList.get(0), is("first"));
 
 // the following is "null" because get(999) was not stubbed
 assertThat(mockedList.get(999), nullValue()); 
  81. ϝιουͷฦ໭஋ͷϞοΫ // you can mock concrete classes, not only interfaces


    LinkedList mockedList = mock(LinkedList.class);
 
 // stubbing appears before the actual execution
 when(mockedList.get(0)).thenReturn("first");
 
 // the following is "first"
 assertThat((String) mockedList.get(0), is("first"));
 
 // the following is "null" because get(999) was not stubbed
 assertThat(mockedList.get(999), nullValue()); 
  82. ϝιουͷฦ໭஋ͷϞοΫ // you can mock concrete classes, not only interfaces


    LinkedList mockedList = mock(LinkedList.class);
 
 // stubbing appears before the actual execution
 when(mockedList.get(0)).thenReturn("first");
 
 // the following is "first"
 assertThat((String) mockedList.get(0), is("first"));
 
 // the following is "null" because get(999) was not stubbed
 assertThat(mockedList.get(999), nullValue()); 
  83. GithubNetworkͷςετ File file = new File("src/test/assets/json/github_contributors.json");
 MockWebServer mockWebServer = new

    MockWebServer();
 mockWebServer.enqueue(ResponseUtil.createMockResponse(file));
 mockWebServer.start();
 
 GithubNetwork githubNetwork = GithubNetwork.getInstance();
 githubNetwork = spy(githubNetwork);
 when(githubNetwork.getBaseUrl())
 .thenReturn(mockWebServer.url("/").toString());
 
 TestSubscriber<List<Contributor>> testSubscriber = new TestSubscriber<>();
 githubNetwork.getContributors().subscribe(testSubscriber);
 
 testSubscriber.assertNoErrors();
 testSubscriber.assertCompleted();
 List<Contributor> contributors = testSubscriber.getOnNextEvents().get(0);
 assertThat(contributors.size(), is(1)); 
  84. GithubNetworkͷςετ File file = new File("src/test/assets/json/github_contributors.json");
 MockWebServer mockWebServer = new

    MockWebServer();
 mockWebServer.enqueue(ResponseUtil.createMockResponse(file));
 mockWebServer.start();
 
 GithubNetwork githubNetwork = GithubNetwork.getInstance();
 githubNetwork = spy(githubNetwork);
 when(githubNetwork.getBaseUrl())
 .thenReturn(mockWebServer.url("/").toString());
 
 TestSubscriber<List<Contributor>> testSubscriber = new TestSubscriber<>();
 githubNetwork.getContributors().subscribe(testSubscriber);
 
 testSubscriber.assertNoErrors();
 testSubscriber.assertCompleted();
 List<Contributor> contributors = testSubscriber.getOnNextEvents().get(0);
 assertThat(contributors.size(), is(1)); 
  85. GithubNetworkͷςετ File file = new File("src/test/assets/json/github_contributors.json");
 MockWebServer mockWebServer = new

    MockWebServer();
 mockWebServer.enqueue(ResponseUtil.createMockResponse(file));
 mockWebServer.start();
 
 GithubNetwork githubNetwork = GithubNetwork.getInstance();
 githubNetwork = spy(githubNetwork);
 when(githubNetwork.getBaseUrl())
 .thenReturn(mockWebServer.url("/").toString());
 
 TestSubscriber<List<Contributor>> testSubscriber = new TestSubscriber<>();
 githubNetwork.getContributors().subscribe(testSubscriber);
 
 testSubscriber.assertNoErrors();
 testSubscriber.assertCompleted();
 List<Contributor> contributors = testSubscriber.getOnNextEvents().get(0);
 assertThat(contributors.size(), is(1)); 
  86. GithubNetworkͷςετ File file = new File("src/test/assets/json/github_contributors.json");
 MockWebServer mockWebServer = new

    MockWebServer();
 mockWebServer.enqueue(ResponseUtil.createMockResponse(file));
 mockWebServer.start();
 
 GithubNetwork githubNetwork = GithubNetwork.getInstance();
 githubNetwork = spy(githubNetwork);
 when(githubNetwork.getBaseUrl())
 .thenReturn(mockWebServer.url("/").toString());
 
 TestSubscriber<List<Contributor>> testSubscriber = new TestSubscriber<>();
 githubNetwork.getContributors().subscribe(testSubscriber);
 
 testSubscriber.assertNoErrors();
 testSubscriber.assertCompleted();
 List<Contributor> contributors = testSubscriber.getOnNextEvents().get(0);
 assertThat(contributors.size(), is(1)); 
  87. GithubNetworkͷςετ File file = new File("src/test/assets/json/github_contributors.json");
 MockWebServer mockWebServer = new

    MockWebServer();
 mockWebServer.enqueue(ResponseUtil.createMockResponse(file));
 mockWebServer.start();
 
 GithubNetwork githubNetwork = GithubNetwork.getInstance();
 githubNetwork = spy(githubNetwork);
 when(githubNetwork.getBaseUrl())
 .thenReturn(mockWebServer.url("/").toString());
 
 TestSubscriber<List<Contributor>> testSubscriber = new TestSubscriber<>();
 githubNetwork.getContributors().subscribe(testSubscriber);
 
 testSubscriber.assertNoErrors();
 testSubscriber.assertCompleted();
 List<Contributor> contributors = testSubscriber.getOnNextEvents().get(0);
 assertThat(contributors.size(), is(1)); 
  88. ໨࣍ • ςετ͕ͳ͍ͱͲ͏ਏ͍ͷ͔ • Couplesͷઃܭ • ςελϏϦςΟͷߴ͍ઃܭ • ςετख๏ɾϑϨʔϜϫʔΫ •

    αϯϓϧΞϓϦͰͷςετ • ςετΛॻ͘จԽΛ࡞ΔͨΊʹ • ·ͱΊ 
  89. ςετΛॻ͘จԽΛ࡞ΔͨΊʹ • ि1ͰษڧձΛ։࠵ • AndroidνʔϜ͸10໊ • ςετ͕ॻ͚Δ؀ڥΛ࡞Δ͚ͩͰ͸ෆे෼ • ਖ਼௚͜Ε͕Ұ൪ॏཁ 

  90. ษڧձ • ΞʔΩςΫνϟʹ͍ͭͯ • Ұൠతͳςετʹ͍ͭͯ • AndroidͰͷςετʹ͍ͭͯ • ςετΛॻ͘ࡍͷTips 

  91. ΞʔΩςΫνϟʹ͍ͭͯ • ৽͍͠ΞʔΩςΫνϟͷ֓ཁ • ৽͍͠ϥΠϒϥϦ • Retrofit • OkHttp •

    RxJava • Gson 
  92. Ұൠతͳςετʹ͍ͭͯ • ιϑτ΢ΣΞςετ • ϗϫΠτ/ϒϥοΫϘοΫεςετ • ಉ஋/ڥք஋ • ໋ྩ/෼ذ/৚݅໢ཏ 

  93. AndroidͰͷςετʹ͍ͭͯ • ςετϑϨʔϜϫʔΫ • JUnit4 • Espresso • Robolectric 

  94. ςετΛॻ͘ࡍͷTips • ςετͷ෭࡞༻ • Observableͷςετํ๏ • ඇಉظॲཧͷςετ 

  95. ໨࣍ • ςετ͕ͳ͍ͱͲ͏ਏ͍ͷ͔ • Couplesͷઃܭ • ςελϏϦςΟͷߴ͍ઃܭ • ςετख๏ɾϑϨʔϜϫʔΫ •

    αϯϓϧΞϓϦͰͷςετ • ςετΛॻ͘จԽΛ࡞ΔͨΊʹ • ·ͱΊ 
  96. ·ͱΊ • ςετ͕ͳ͍ͱͲ͏ਏ͍ͷ͔ • ๲େͳςετέʔεʹΑΔਓతϦιʔεͷ ࿘අ΍༧ظͤ͵όά • ػձଛࣦ 

  97. ·ͱΊ • Couplesͷݱঢ়ͷઃܭ • Activity/Fragment͕Ϛονϣ • όοΫΤϯυͷґଘؔ܎͕ෳࡶ 

  98. ·ͱΊ • ςελϏϦςΟͷߴ͍ઃܭ • UI͸සൟʹมߋ͞ΕΔͨΊɺ·ͣ͸όοΫΤϯυ͔Β ߈ΊΔ • σʔλऔಘϩδοΫΛActivity/Fragment͔Β෼཭ • AndroidʹґଘͤͣςετՄೳʹ

    
  99. ·ͱΊ • ςετख๏ • Ϣχοτςετ • UIςετ • ςετϑϨʔϜϫʔΫ •

    JUnit4 • Espresso • Robolectric 
  100. ·ͱΊ • αϯϓϧΞϓϦͰͷςετ • GithubͷContributorsΛදࣔ • Database, Serviceͷςετ 

  101. ·ͱΊ • ςετΛॻ͘จԽΛ࡞ΔͨΊʹ • ि1Ͱษڧձ • ςετ͕ॻ͚Δ؀ڥΛ࡞Δ͚ͩͰ͸ෆे෼ Ͱɺ͜Ε͕Ұ൪ॏཁ͔΋ 

  102. ͍͞͝ʹ • ςετ͕໨తԽͯ͠͸μϝ • ָΛ͍ͨ͠ • ΤϯδχΞ͸ଵଦͰ͋Ε • ༗ӹͳ͜ͱʹۀ຿࣌ؒΛ࢖͑ΔΑ͏ʹͳΕ͹ɺ ΤϯδχΞ΋Ϣʔβʔ΋ϋοϐʔʂ

    
  103.  ΤϯδχΞ ઈࢍ࠾༻தʂ ฐࣾ$%0 ʢνʔϑɾυοάɾΦϑΟαʔʣ ͝ਗ਼ௌ ͋Γ͕ͱ͏͍͟͝·ͨ͠ʂ

  104. Thank you :) Credit: NASA Earth Observatory/NOAA NGDC

  105. ิ଍ࢿྉ 

  106. ResponseUtil public class ResponseUtil {
 
 public static MockResponse createMockResponse(


    File file) throws IOException {
 BufferedSource source = Okio.buffer(Okio.source(file));
 StringBuilder builder = new StringBuilder();
 while (!source.exhausted()) {
 builder.append(source.readUtf8Line());
 }
 
 MockResponse mockResponse = new MockResponse();
 mockResponse.setBody(builder.toString());
 
 return mockResponse;
 }
 
 } 
  107. GithubRepository public static Observable<List<Contributor>> getContributors() {
 return Observable.concat(
 GithubDatabase.getContributors(),
 GithubNetwork.getInstance().getContributors())


    .subscribeOn(Schedulers.newThread())
 .observeOn(AndroidSchedulers.mainThread());
 } 
  108. GithubRepository  http://reactivex.io/documentation/operators/concat.html