Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Android Testing Bootcamp #3 Hands-On
Search
Fumihiko Shiroyama
September 09, 2016
Technology
4
750
Android Testing Bootcamp #3 Hands-On
Android Testing Bootcamp #3 Hands-On 資料
Fumihiko Shiroyama
September 09, 2016
Tweet
Share
More Decks by Fumihiko Shiroyama
See All by Fumihiko Shiroyama
The world of Android wireless communications without Internet
srym
1
140
AWS Device FarmとCircleCIでAndroidのUIテストを自動化しよう
srym
1
5.1k
Spring BootをKotlinで作成しAmazon Elastic Container Service (ECS) で稼働させる
srym
6
2k
iOSDC_2019_DeviceFarm.pdf
srym
8
20k
世界で戦うエンジニアになるために_公開用.pdf
srym
18
45k
Unit Testing in a Nutshell - DroidKaigi 2018
srym
11
15k
Clean Architecture & TDD
srym
1
3.8k
はやい・やすい・うまい!スタートアップでも使える Retrofit + RxJava で瞬間APIクッキングレシピ
srym
2
630
I/O 2017 Short Report
srym
0
310
Other Decks in Technology
See All in Technology
Microsoft の SSE の現在地
skmkzyk
0
150
ここはMCPの夜明けまえ
nwiizo
30
11k
クラウド開発環境Cloud Workstationsの紹介
yunosukey
0
190
Porting PicoRuby to Another Microcontroller: ESP32
yuuu
4
460
Running JavaScript within Ruby
hmsk
3
360
2025-04-24 "Manga AI Understanding & Localization" Furukawa Arata (CyberAgent, Inc)
ornew
2
250
Oracle Cloud Infrastructure:2025年4月度サービス・アップデート
oracle4engineer
PRO
0
120
AIコーディングの最前線 〜活用のコツと課題〜
pharma_x_tech
4
2.4k
今日からはじめるプラットフォームエンジニアリング
jacopen
8
1.6k
Winning at PHP in Production in 2025
beberlei
1
150
Road to Go Gem #rubykaigi
sue445
0
930
AWS全冠芸人が見た世界 ~資格取得より大切なこと~
masakiokuda
5
6.4k
Featured
See All Featured
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
656
60k
jQuery: Nuts, Bolts and Bling
dougneiner
63
7.7k
Documentation Writing (for coders)
carmenintech
69
4.7k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
104
19k
A Tale of Four Properties
chriscoyier
158
23k
Code Reviewing Like a Champion
maltzj
522
40k
Statistics for Hackers
jakevdp
798
220k
Embracing the Ebb and Flow
colly
85
4.7k
Fontdeck: Realign not Redesign
paulrobertlloyd
83
5.5k
Mobile First: as difficult as doing things right
swwweet
223
9.6k
YesSQL, Process and Tooling at Scale
rocio
172
14k
Designing for Performance
lara
608
69k
Transcript
"OESPJE5FTUJOH#PPUDBNQ )BOET0O "OESPJE@5FTUJOH@#$
w "OESPJE5FTUJOH#PPUDBNQ(SPVQ w IUUQBOESPJEUFTUJOH CPPUDBNQDPOOQBTTDPN w "OESPJE5FTUJOH#PPUDBNQ w IUUQBOESPJEUFTUJOH CPPUDBNQDPOOQBTTDPNFWFOU
ࠓճར༻͢Δڥ
w "OESPJE4UVEJP w IUUQTHJUIVCDPNTSZN5FTU)BOET0O w HJUDMPOFHJU!HJUIVCDPNTSZN 5FTU)BOET0OHJU w HJUDPFYBNQMFྫϒϥϯν w
HJUDPBOTXFSղྫϒϥϯν
ΞδΣϯμ
w ͳͥςετΛॻ͘ͷ͔ w ςετͷछྨ w +6OJU w .PDLJUP w 1PXFS.PDL
w %PHHFS 6*ςετ ࣍ճϋϯζΦϯΛ ָ͓͠Έʹʂ
ͳͥςετΛॻ͘ͷ͔
w ϩδοΫͷݕূ w ༷มߋͷै w σάϨͷݕग़ w ઃܭͷݟ͠ͷ͖͔͚ͬ
ςετͷछྨ
w ୯ମςετ 6OJU5FTU w ݁߹ςετ *OUFHSBUJPO5FTU w Ϣʔβड͚ೖΕςετ
6TFS"DDFQUBODF5FTU w ͦͷଞɺෛՙςετɾηΩϡϦςΟςετ
6OJU5FTU w ϓϩάϥϚ͕࣮ w ϝιουΫϥεʹରʹରԠ w ࣗಈ࣮ߦ w ߴ w
"OESPJEͷ߹ɺ࣮ػڥͰͳ͍͜ͱ͕ଟ͍
*OUFHSBUJPO5FTU w 6*ʹର͢ΔࣗಈςετΛؚΉ w ࣮ࡍͷը໘ભҠ*0ॲཧɺωοτϫʔΫ௨৴Λߦ ͏͜ͱଟ͍ w ࣮ػʢΤϛϡϨʔλؚΉʣ࣮ߦ ఆٛӡ༻ ݱʹΑͬͯҧ͏
ड͚ೖΕςετ w ൃݩɺϚωʔδϟɾσΟϨΫλ͕֬ೝ w 2"͞ΜɺςελʹΑΔ֬ೝ w ଟ͘ͷ߹खಈ ఆٛӡ༻ ݱʹΑͬͯҧ͏
ͦͷଞ w ෛՙςετ w ηΩϡϦςΟςετ w ͦͷଞॾʑ
+6OJU
w "OESPJEͷ6OJU5FTUͷσϑΝΫτελϯμʔυ w "OESPJE4UVEJPҎ߱Λ͍ͬͯΕԿ͠ͳ͘ ͯར༻Մೳ w Ξϊςʔγϣϯϕʔε w +7.ڥͷΈͰಈ࡞͠ඇৗʹߴ
CVJMEHSBEMF EFQFOEFODJFT\ DPNQJMFpMF5SFF EJSMJCT JODMVEF< KBS> UFTU$PNQJMFKVOJUKVOJU DPNQJMFDPNBOESPJETVQQPSUBQQDPNQBUW ^
+6OJUͷجຊ
w NPEVMFTSDUFTUKBWBQBDLBHF5BSHFU5FTUKBWB w !#FGPSFʜॳظԽ w !"GUFSʜޙॲཧ w !5FTUʜςετίʔυຊମ
public class CalculatorTest { private Calculator calculator; @Before public
void setUp() { calculator = new Calculator(); } @After public void tearDown() { } @Test public void ͠ࢉ͕ਖ਼͘͠ग़དྷΔ() throws Exception { double expected = calculator.add(1.0, 2.0); assertTrue(expected == 3.0); } }
"TTFSUJPO w "TTFSUBTTFSU5SVF CPPMFBODPOEJUJPO w "TTFSUBTTFSU&RVBMT 0CKFDUFYQFDUFE 0CKFDU BDUVBM
՝ w )FMMP+6OJUΛͤ͞Α͏ʂ w IUUQTHJUIVCDPNTSZN5FTU)BOET0OCMPC FYBNQMFKVOJUTSDUFTUKBWBVTTIJSPZBNBBOESPJE KVOJU)FMMP+6OJUKBWB w
$BMDVMBUPS5FTUΛͤ͞Α͏ʂ w IUUQTHJUIVCDPNTSZN5FTU)BOET0OCMPC FYBNQMFKVOJUTSDUFTUKBWBVTTIJSPZBNBBOESPJE KVOJU$BMDVMBUPS5FTUKBWB
.BUDIFS w .BUDIFSʜʮͲΜͳঢ়ଶ͔ʯΛද͢ w "TTFSUBTTFSU5IBU BDUVBM NBUDIFS w )BNDSFTUͷ.BUDIFST͕༗໊
w IUUQIBNDSFTUPSH+BWB)BNDSFTU
Assert.assertThat(1 + 1, Matchers.is(2)); assertThat("MIKE", is(not("STEVE"))); assertThat(1000L, is(instanceOf(Integer.class)));
EFQFOEFODJFT\ UFTU$PNQJMFKVOJUKVOJU UFTU$PNQJMFPSHIBNDSFTUIBNDSFTUMJCSBSZ ^
Α͘͏.BUDIFS w JT ʜಉ w OPU ʜ൱ఆ w OVMM7BMVF OPU/VMM7BMVF
ʜ/VMMʗඇ/VMM w TBNF*OTUBODF ʜಉҰΠϯελϯε w JOTUBODF0G ʜಉҰ͔αϒΫϥεͷΠϯελϯε w TUBSUT8JUI FOET8JUI ʜࢦఆจࣈྻͰ࢝·ΔʗऴΘΔ w DPOUBJOT4USJOH ʜࢦఆจࣈྻؚ͕·ΕΔ w JT&NQUZ4USJOH ʜۭจࣈྻ
w HSFBUFS5IBO HSFBUFS5IBO0S&RVBM5P ʜΑΓେ͖͍ʗҎ ্ w MFTT5IBO MFTT5IBO0S&RVBM5P ʜΑΓখ͍͞ʗҎԼ w
DMPTF5P ʜࢦఆͷൣғ͔Ͳ͏͔ w BTTFSU5IBU JT DMPTF5P ʙൣ ғͳͷͰUSVF w ͦͷଞɺϦετϚοϓ༻ͷ.BUDIFSଟ w ࢀߟ IUUQRJJUBDPNPQFOHMJUFNT FEBCFGBB
՝ w $BMDVMBUPS5FTU8JUI)BNDSFTU.BUDIFSTΛ ͤ͞Α͏ʂ w IUUQTHJUIVCDPNTSZN5FTU)BOET0OCMPC FYBNQMFKVOJUTSDUFTUKBWBVTTIJSPZBNB BOESPJEKVOJU $BMDVMBUPS5FTU8JUI)BNDSFTU.BUDIFSTKBWB
.PDLJUP
w ϝιουΛ͋Β͔͡ΊܾΊΒΕͨ݁Ռ͕ฦΔΑ͏ʹ ϞοΫΞοϓ͢Δ w *0ɺωοτϫʔΫΞΫηεɺϥϯμϜੑͷഉআ w ͦͷͰςετ͍߲ͨ͠ʹूத͢Δ w .PDLJUP͕σϑΝΫτελϯμʔυ
public class RandomIntGenerator { private final Random random = new
Random(); public int generate() { return random.nextInt(Integer.MAX_VALUE); } }
public class RandomIntGeneratorTest { private RandomIntGenerator randomIntGenerator; @Before public
void setUp() { randomIntGenerator = new RandomIntGenerator(); } @After public void tearDown() { } @Test public void generateͷ݁Ռ() { int expected = randomIntGenerator.generate(); assertThat(expected, is(1)); // ͜Μͳ͜ͱͰ͖ͳ͍ʂʂ } }
͍ํ RandomIntGenerator randomIntGenerator = Mockito.mock(RandomIntGenerator.class); Mockito.when(randomIntGenerator.generate()).thenReturn(123);
w ଞʹ!.PDLΞϊςʔγϣϯΛ͏Γํ͕͋Δ
@Mock RandomIntGenerator randomIntGeneratorWithAnnotation; @Before public void setUp() {
MockitoAnnotations.initMocks(this); Mockito.when(randomIntGeneratorWithAnnotation.generate()).thenReturn(456); }
՝ w 3BOEPN*OU(FOFSBUPS5FTUΛͤ͞Α͏ʂ w IUUQTHJUIVCDPNTSZN5FTU)BOET0OCMPC FYBNQMFNPDLJUPTSDUFTUKBWBVTTIJSPZBNB BOESPJENPDLJUP 3BOEPN*OU(FOFSBUPS5FTUKBWB w
!.PDLΞϊςʔγϣϯΛ͏ํ๏ࢼͯ͠ΈΑ ͏ʂ
.PDLJUPWFSJGZ
w .PDLΦϒδΣΫτɺݺͼग़͠Λͯ͢هԱͯ͠ ͍Δ w ݺͼग़͞ΕͨϝιουɺճɺҾͳͲΛ .PDLJUPWFSJGZͰݕূͰ͖Δ
Mockito.verify(mockStrings, Mockito.times(1)).add("FOO"); Mockito.verify(mockStrings, Mockito.atLeast(1)).add("BAR"); Mockito.verify(mockStrings).add("BAZ"); Mockito.verify(mockStrings, Mockito.never()).add("I AM NOT CALLED");
EFQFOEFODJFT\ UFTU$PNQJMFKVOJUKVOJU UFTU$PNQJMFPSHIBNDSFTUIBNDSFTUMJCSBSZ UFTU$PNQJMFPSHNPDLJUPNPDLJUPDPSF ^
.PDLJUPTQZ
w ΦϒδΣΫτΛͦͷ··ϞοΫΞοϓ͢Δ .PDLJUPNPDLʹର͠ɺTQZ࣮ΦϒδΣΫτͷҰ ෦ͷΈΛࠩ͠ସ͑ΒΕΔ w TQZΦϒδΣΫτNPDLͱಉ༷WFSJGZͰݕূͰ͖Δ w TQZͰΛฦ͢ͱ͖ XIFO NPDL
UIFO3FUVSO WBMVF Ͱͳ͘ EP3FUVSO WBMVF XIFO NPDL NFUIPE Λ͏ w !.PDLಉ༷ɺ!4QZΞϊςʔγϣϯ͕ར༻Մೳ
List<String> realList = new ArrayList<>(); List<String> spyList = spy(realList); doReturn(38).when(spyList).size();
ϑΟʔϧυʹ.PDLΛ ૹΓ͜Ή
public class StringCollector { private List<String> strings = new ArrayList<>();
public void add(@NonNull String string) { strings.add(string); } public int size() { return strings.size(); } }
w ϑΟʔϧυͷ"SSBZ-JTUʹͲ͏ͬͯϞοΫΛૹΓ ࠐΉʁ w TFUUFSΛ༻ҙͯ͠!7JTJCMF'PS5FTUJOH w !*OKFDU.PDLTΞϊςʔγϣϯ
public class StringCollector { private List<String> strings = new ArrayList<>();
public void add(@NonNull String string) { strings.add(string); } public int size() { return strings.size(); } @VisibleForTesting void setStrings(List<String> strings) { this.strings = strings; } }
!*OKFDU.PDLT @Mock List<String> mockStringsForInject; @InjectMocks StringCollector stringCollectorForInject;
՝ w 4USJOH$PMMFDUPS5FTUΛͤ͞Α͏ʂ w IUUQTHJUIVCDPNTSZN5FTU)BOET0OCMPC FYBNQMFNPDLJUPTSDUFTUKBWBVTTIJSPZBNB BOESPJENPDLJUP4USJOH$PMMFDUPS5FTUKBWB w
!4QZΞ ϊςʔγϣϯΛ͏ํ๏ࢼͯ͠ΈΑ͏ʂ w !*OKFDU.PDLTΞϊςʔγϣϯͬͯΈΑ͏ʂ
.PDLJUPࢀߟϦϯΫ w IUUQFUDIBUFOBCMPHDPNFOUSZ w IUUQFUDIBUFOBCMPHDPNFOUSZ w IUUQFUDIBUFOBCMPHDPNFOUSZ
1PXFS.PDL
w ࠓճ͕࣌ؒͳ͍ͷͰ৮Ε·ͤΜ w pOBMDMBTTTUBUJDNFUIPEΛϞοΫͰ͖Δ w Ϋϥεϩʔμʹհೖ͢ΔͷͰϋϚϦϙΠϯτ͕͍ͬ ͺ͍͋Δ w ಟʹༀʹͳΓ͏Δ
ςετ͍͢͠ߏԽ
w DPNNPOϞδϡʔϧͷ6TFS*OGP6TFS$BTFͷղઆ w IUUQTHJUIVCDPNTSZN5FTU)BOET0OCMPC FYBNQMFDPNNPOTSDNBJOKBWBVT TIJSPZBNBBOESPJEDPNNPOVTFDBTF 6TFS*OGP6TF$BTF*NQMKBWB
՝ w 6TFS*OGP6TF$BTF*NQM5FTUΛͤ͞Α͏ʂ w IUUQTHJUIVCDPNTSZN5FTU)BOET0OCMPC FYBNQMFNPDLJUPTSDUFTUKBWBVTTIJSPZBNB BOESPJENPDLJUP 6TFS*OGP6TF$BTF*NQM5FTUKBWB w
ඇಉظॲཧͷςετͷώϯτɿ$PVOU%PXO-BUDI
w ςετΛͳΔ͍͘͢͠ߏʹ͢Δ w దʹΠϯλϑΣʔεΛΔ w ґଘੑΛίϯετϥΫλͰ͢ w %*ίϯςφΛ͏
%BHHFS
w (PPHMF͕ϝϯςφϯε͍ͯ͠Δ%*ίϯςφ w IUUQHPPHMFHJUIVCJPEBHHFS w .PEVMFͱ$PNQPOFOUΛͬͯґଘੑͷάϥϑΛ ఆٛ͠ɺ!*OKFDUΞϊςʔγϣϯͰ࣮Πϯελϯε Λࠩ͠ࠐΉ w ςετ࣌ʹΠϯελϯεΛΓସ͑ΒΕΔͳͲॊೈ
ੑ͕૿͢
@Module public class ApplicationModule { @Singleton @Provides public MessageHelper provideMessageHelper(Context
context) { return MessageHelper.getInstance(context); } }
@Singleton @Component(modules = ApplicationModule.class) public interface ApplicationComponent { ActivityComponent activityComponent(ActivityModule
module); }
public ApplicationComponent getComponent() { return applicationComponent; } @Override public
void onCreate() { super.onCreate(); applicationComponent = DaggerApplicationComponent.builder() .applicationModule(new ApplicationModule(this)) .build(); }
public class BaseActivity extends AppCompatActivity { private ActivityComponent activityComponent;
/** * {@link android.app.Activity}ͷґଘੑάϥϑΛฦ͢ * * @return */ protected ActivityComponent getComponent() { if (activityComponent == null) { MyApplication myApplication = (MyApplication) getApplication(); activityComponent = myApplication.getComponent().activityComponent(new ActivityModule(this)); } return activityComponent; } }
public class ChatActivity extends BaseActivity { @Inject MessageHelper messageHelper;
// ҎԼུ }
w %BHHFSΛ࣮ͬͨફతͳྫOVNBࢯʹҾ͖ܧ͗ ·͢ʂ