Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

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

Slide 4

Slide 4 text

Android൛Λ୲౰ ↓

Slide 5

Slide 5 text

Couples 

Slide 6

Slide 6 text

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

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

CouplesͰͷྫ • ๲େͳςετέʔεͷਓྗ֬ೝ • ӨڹൣғͷߟྀϛεʹΑΔόά • ςετέʔεͷෳࡶԽ 

Slide 10

Slide 10 text

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

Slide 11

Slide 11 text

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

Slide 12

Slide 12 text

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

Slide 13

Slide 13 text

ͦͷଞը໘ • ϓϩϑΟʔϧʹભҠ͢Δ͜ͱ • ͓ؾʹೖΓʹભҠ͢Δ͜ͱ • ώετϦʔʹભҠ͢Δ͜ͱ • etc…  ࣗಈԽग़དྷΔͰ͠ΐɺɺ

Slide 14

Slide 14 text

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

Slide 15

Slide 15 text

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

Slide 16

Slide 16 text

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

Slide 17

Slide 17 text

͓͡͞Μ͸͜͏ߟ͑ͨ 

Slide 18

Slide 18 text

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

Slide 19

Slide 19 text

Α͠ɺςετΛॻ͜͏ 

Slide 20

Slide 20 text

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

Slide 21

Slide 21 text

ɾɾɾɾɾ 

Slide 22

Slide 22 text

ςετ͕ॻ͚ͳ͍ɾɾɾ 

Slide 23

Slide 23 text

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

Slide 24

Slide 24 text

ݱঢ়ͷઃܭ  View Activity/Fragment Model Request DB Server

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

͓͡͞Μͷબ୒ࢶ • طଘͷόοΫΤϯυʹ௚઀खΛೖΕΔ • ৽͍͠όοΫΤϯυΛ࡞ͬͯ৐Γ׵͑ 

Slide 27

Slide 27 text

͓͡͞Μͷܾஅ • طଘͷόοΫΤϯυʹ௚઀खΛೖΕΔ • ґଘؔ܎͕ෳࡶ • ςετ͕ͳ͍ঢ়ଶͰखΛೖΕΔͷ͕ා͍ • ৽͍͠όοΫΤϯυΛ࡞ͬͯ৐Γ׵͑ • ґଘؔ܎Λ៉ྷʹ੔ཧ • ςετΛॻ͖ͳ͕Βػೳ୯ҐͰॱ࣍ஔ͖׵͑Δ͜ͱ ͰϦεΫΛԼ͛Δ 

Slide 28

Slide 28 text

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

Slide 29

Slide 29 text

ςελϏϦςΟΛߴΊΔͨΊʹ͸ • ֤૚ͷ໾ׂ͕໌֬ • ద੾ͳϞδϡʔϧԽ • CIαʔόʔͰܧଓతͳςετ͕Մೳ 

Slide 30

Slide 30 text

৽͍͠ઃܭ  View Activity/Fragment Repository Database Network DB Server Model ϑϩϯτΤϯυ όοΫΤϯυ

Slide 31

Slide 31 text

όοΫΤϯυ  Repository Database Network DB Server ActiveAndroid Retrofit × OkHttp Observable Observable

Slide 32

Slide 32 text

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

Slide 33

Slide 33 text

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

Slide 34

Slide 34 text

MVC  Model View Controller Activity/Fragment UIΠϕϯτ ߋ৽ Ϟσϧૢ࡞ ߋ৽σʔλ جຊతʹ͸௚઀ࢀর͠ͳ͍

Slide 35

Slide 35 text

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

Slide 36

Slide 36 text

MVP  Model View Presenter Activity/Fragment UIΠϕϯτ ߋ৽ Ϟσϧૢ࡞ ߋ৽σʔλ جຊతʹ͸௚઀ࢀর͠ͳ͍

Slide 37

Slide 37 text

MVP • ϝϦοτ • ੹຿ͷ෼཭ • Activity/Fragment = View • Presenter = Controller • σϝϦοτ • Ϋϥε਺͕ଟ͘ͳΔ • νʔϜ։ൃͷ৔߹͸͋Δఔ౓υΩϡϝϯτ͕ඞཁ 

Slide 38

Slide 38 text

ϑϩϯτΤϯυ • ৭ʑͳΞʔΩςΫνϟ͕ଘࡏ͢Δ͕ɺ·ͩࣗ ෼ͷதͰෲམͪͰ͖͍ͯͳ͍ • ݁ہ͸ςετΛॻ͘͜ͱ͕໨తͳͷͰɺಛఆ ͷΞʔΩςΫνϟʹͩ͜ΘΔ΂͖͡Όͳ͍ • όοΫΤϯυΛ៉ྷʹͨ͜͠ͱͰɺϑϩϯτ ΋͋Δఔ౓៉ྷʹͳͬͨͷͰɺςετ͕ॻ͚ ͦ͏ 

Slide 39

Slide 39 text

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

Slide 40

Slide 40 text

ςετख๏ • Ϣχοτςετ • ϝιου୯ҐͰϩδοΫͷଥ౰ੑΛςετ ͢Δ͜ͱ • UIςετ • UIͷಈ͖΋ؚΊͨςετΛ͢Δ͜ͱ 

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

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

Slide 43

Slide 43 text

Espresso • Testing Support Library • UIͷಈ͖΋ؚΊͨςετ͕ॻ͚Δ • ࣮ػ্Ͱςετ࣮ߦ • ਓ͕ؒૢ࡞͢Δͷͱಉ༷ͷ͕͔͔࣌ؒΔ 

Slide 44

Slide 44 text

Espresso 

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

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

Slide 47

Slide 47 text

αϯϓϧ࣮૷ • konifar/droidkaigi2016ͷContributorsΛදࣔ • yuyakaido/android-genesis 

Slide 48

Slide 48 text

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;
 
 } 

Slide 49

Slide 49 text

GithubDatabase public static Observable> getContributors() {
 return Database.getDatabase()
 .selectFromContributor()
 .executeAsObservable()
 .toList();
 } 

Slide 50

Slide 50 text

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

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

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

Slide 53

Slide 53 text

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

Slide 54

Slide 54 text

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

Slide 55

Slide 55 text

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

Slide 56

Slide 56 text

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

Slide 57

Slide 57 text

GithubDatabaseͷςετ final int COUNT = 10;
 List 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> testSubscriber = new TestSubscriber<>();
 GithubDatabase.getContributors().subscribe(testSubscriber);
 
 testSubscriber.assertNoErrors();
 testSubscriber.assertCompleted();
 List result = testSubscriber.getOnNextEvents().get(0);
 assertThat(result.size(), is(contributors.size())); 

Slide 58

Slide 58 text

GithubDatabaseͷςετ final int COUNT = 10;
 List 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> testSubscriber = new TestSubscriber<>();
 GithubDatabase.getContributors().subscribe(testSubscriber);
 
 testSubscriber.assertNoErrors();
 testSubscriber.assertCompleted();
 List result = testSubscriber.getOnNextEvents().get(0);
 assertThat(result.size(), is(contributors.size())); 

Slide 59

Slide 59 text

TestSubscriber • RxJavaͷςετ༻Ϋϥε • ΠϕϯτΛه࿥ͯ͘͠ΕΔศརͳ΍ͭ • onNext(), onError(), onCompleted()ͰassertΛ ॻ͍ͯ΋͍͍͚Ͳ΋ɺɺɺ 

Slide 60

Slide 60 text

TestSubscriber Integer[] integers = new Integer[] {1, 2, 3};
 Observable observable = Observable.from(integers);
 
 observable.subscribe(new Subscriber() {
 @Override
 public void onCompleted() {}
 
 @Override
 public void onError(Throwable e) {}
 
 @Override
 public void onNext(Integer integer) {
 throw new RuntimeException();
 }
 }); 

Slide 61

Slide 61 text

TestSubscriber @Test
 public void subscriberTest() {
 Integer[] integers = new Integer[] {1, 2, 3};
 Observable observable = Observable.from(integers);
 
 TestSubscriber testSubscriber = new TestSubscriber<>();
 observable.subscribe(testSubscriber);
 
 testSubscriber.assertNoErrors();
 testSubscriber.assertValueCount(integers.length);
 testSubscriber.assertValues(integers);
 testSubscriber.assertCompleted();
 } 

Slide 62

Slide 62 text

GithubDatabaseͷςετ final int COUNT = 10;
 List 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> testSubscriber = new TestSubscriber<>();
 GithubDatabase.getContributors().subscribe(testSubscriber);
 
 testSubscriber.assertNoErrors();
 testSubscriber.assertCompleted();
 List result = testSubscriber.getOnNextEvents().get(0);
 assertThat(result.size(), is(contributors.size())); 

Slide 63

Slide 63 text

GithubDatabaseͷςετ final int COUNT = 10;
 List 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> testSubscriber = new TestSubscriber<>();
 GithubDatabase.getContributors().subscribe(testSubscriber);
 
 testSubscriber.assertNoErrors();
 testSubscriber.assertCompleted();
 List result = testSubscriber.getOnNextEvents().get(0);
 assertThat(result.size(), is(contributors.size())); 

Slide 64

Slide 64 text

GithubDatabaseͷςετ final int COUNT = 10;
 List 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> testSubscriber = new TestSubscriber<>();
 GithubDatabase.getContributors().subscribe(testSubscriber);
 
 testSubscriber.assertNoErrors();
 testSubscriber.assertCompleted();
 List result = testSubscriber.getOnNextEvents().get(0);
 assertThat(result.size(), is(contributors.size())); 

Slide 65

Slide 65 text

GithubDatabaseͷςετ final int COUNT = 10;
 List 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> testSubscriber = new TestSubscriber<>();
 GithubDatabase.getContributors().subscribe(testSubscriber);
 
 testSubscriber.assertNoErrors();
 testSubscriber.assertCompleted();
 List result = testSubscriber.getOnNextEvents().get(0);
 assertThat(result.size(), is(contributors.size())); 

Slide 66

Slide 66 text

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> testSubscriber = new TestSubscriber<>();
 githubNetwork.getContributors().subscribe(testSubscriber);
 
 testSubscriber.assertNoErrors();
 testSubscriber.assertCompleted();
 List contributors = testSubscriber.getOnNextEvents().get(0);
 assertThat(contributors.size(), is(1)); 

Slide 67

Slide 67 text

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> testSubscriber = new TestSubscriber<>();
 githubNetwork.getContributors().subscribe(testSubscriber);
 
 testSubscriber.assertNoErrors();
 testSubscriber.assertCompleted();
 List contributors = testSubscriber.getOnNextEvents().get(0);
 assertThat(contributors.size(), is(1)); 

Slide 68

Slide 68 text

MockWebServer • square/okhttp/mockwebserver • ໊લͷ௨ΓɺWebαʔόʔͷϞοΫ͕Մೳ • ৴པͷSquare੡ 

Slide 69

Slide 69 text

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

Slide 70

Slide 70 text

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

Slide 71

Slide 71 text

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

Slide 72

Slide 72 text

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

Slide 73

Slide 73 text

Mockito • https://github.com/mockito/mockito • Ϣχοτςετ༻ͷϞοΫϥΠϒϥϦ • ϝιου͕ݺͼग़͞Εͨ͜ͱΛ֬ೝ • ϝιουͷฦ໭஋ΛϞοΫ 

Slide 74

Slide 74 text

ϝιουͷݺͼग़֬͠ೝ // 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(); 

Slide 75

Slide 75 text

ϝιουͷݺͼग़֬͠ೝ // 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(); 

Slide 76

Slide 76 text

ϝιουͷݺͼग़֬͠ೝ // 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(); 

Slide 77

Slide 77 text

ϝιουͷݺͼग़֬͠ೝ // 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(); 

Slide 78

Slide 78 text

ϝιουͷฦ໭஋ͷϞοΫ // 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()); 

Slide 79

Slide 79 text

ϝιουͷฦ໭஋ͷϞοΫ // 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()); 

Slide 80

Slide 80 text

ϝιουͷฦ໭஋ͷϞοΫ // 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()); 

Slide 81

Slide 81 text

ϝιουͷฦ໭஋ͷϞοΫ // 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()); 

Slide 82

Slide 82 text

ϝιουͷฦ໭஋ͷϞοΫ // 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()); 

Slide 83

Slide 83 text

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> testSubscriber = new TestSubscriber<>();
 githubNetwork.getContributors().subscribe(testSubscriber);
 
 testSubscriber.assertNoErrors();
 testSubscriber.assertCompleted();
 List contributors = testSubscriber.getOnNextEvents().get(0);
 assertThat(contributors.size(), is(1)); 

Slide 84

Slide 84 text

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> testSubscriber = new TestSubscriber<>();
 githubNetwork.getContributors().subscribe(testSubscriber);
 
 testSubscriber.assertNoErrors();
 testSubscriber.assertCompleted();
 List contributors = testSubscriber.getOnNextEvents().get(0);
 assertThat(contributors.size(), is(1)); 

Slide 85

Slide 85 text

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> testSubscriber = new TestSubscriber<>();
 githubNetwork.getContributors().subscribe(testSubscriber);
 
 testSubscriber.assertNoErrors();
 testSubscriber.assertCompleted();
 List contributors = testSubscriber.getOnNextEvents().get(0);
 assertThat(contributors.size(), is(1)); 

Slide 86

Slide 86 text

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> testSubscriber = new TestSubscriber<>();
 githubNetwork.getContributors().subscribe(testSubscriber);
 
 testSubscriber.assertNoErrors();
 testSubscriber.assertCompleted();
 List contributors = testSubscriber.getOnNextEvents().get(0);
 assertThat(contributors.size(), is(1)); 

Slide 87

Slide 87 text

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> testSubscriber = new TestSubscriber<>();
 githubNetwork.getContributors().subscribe(testSubscriber);
 
 testSubscriber.assertNoErrors();
 testSubscriber.assertCompleted();
 List contributors = testSubscriber.getOnNextEvents().get(0);
 assertThat(contributors.size(), is(1)); 

Slide 88

Slide 88 text

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

Slide 89

Slide 89 text

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

Slide 90

Slide 90 text

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

Slide 91

Slide 91 text

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

Slide 92

Slide 92 text

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

Slide 93

Slide 93 text

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

Slide 94

Slide 94 text

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

Slide 95

Slide 95 text

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

Slide 96

Slide 96 text

·ͱΊ • ςετ͕ͳ͍ͱͲ͏ਏ͍ͷ͔ • ๲େͳςετέʔεʹΑΔਓతϦιʔεͷ ࿘අ΍༧ظͤ͵όά • ػձଛࣦ 

Slide 97

Slide 97 text

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

Slide 98

Slide 98 text

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

Slide 99

Slide 99 text

·ͱΊ • ςετख๏ • Ϣχοτςετ • UIςετ • ςετϑϨʔϜϫʔΫ • JUnit4 • Espresso • Robolectric 

Slide 100

Slide 100 text

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

Slide 101

Slide 101 text

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

Slide 102

Slide 102 text

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

Slide 103

Slide 103 text

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

Slide 104

Slide 104 text

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

Slide 105

Slide 105 text

ิ଍ࢿྉ 

Slide 106

Slide 106 text

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;
 }
 
 } 

Slide 107

Slide 107 text

GithubRepository public static Observable> getContributors() {
 return Observable.concat(
 GithubDatabase.getContributors(),
 GithubNetwork.getInstance().getContributors())
 .subscribeOn(Schedulers.newThread())
 .observeOn(AndroidSchedulers.mainThread());
 } 

Slide 108

Slide 108 text

GithubRepository  http://reactivex.io/documentation/operators/concat.html