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
730
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
120
AWS Device FarmとCircleCIでAndroidのUIテストを自動化しよう
srym
1
4.9k
Spring BootをKotlinで作成しAmazon Elastic Container Service (ECS) で稼働させる
srym
6
1.9k
iOSDC_2019_DeviceFarm.pdf
srym
8
19k
世界で戦うエンジニアになるために_公開用.pdf
srym
18
45k
Unit Testing in a Nutshell - DroidKaigi 2018
srym
11
15k
Clean Architecture & TDD
srym
1
3.7k
はやい・やすい・うまい!スタートアップでも使える Retrofit + RxJava で瞬間APIクッキングレシピ
srym
2
590
I/O 2017 Short Report
srym
0
300
Other Decks in Technology
See All in Technology
New Relicを活用したSREの最初のステップ / NRUG OKINAWA VOL.3
isaoshimizu
2
610
100 名超が参加した日経グループ横断の競技型 AWS 学習イベント「Nikkei Group AWS GameDay」の紹介/mediajaws202411
nikkei_engineer_recruiting
1
170
OTelCol_TailSampling_and_SpanMetrics
gumamon
1
160
[CV勉強会@関東 ECCV2024 読み会] オンラインマッピング x トラッキング MapTracker: Tracking with Strided Memory Fusion for Consistent Vector HD Mapping (Chen+, ECCV24)
abemii
0
220
20241120_JAWS_東京_ランチタイムLT#17_AWS認定全冠の先へ
tsumita
2
270
【Pycon mini 東海 2024】Google Colaboratoryで試すVLM
kazuhitotakahashi
2
510
BLADE: An Attempt to Automate Penetration Testing Using Autonomous AI Agents
bbrbbq
0
310
テストコード品質を高めるためにMutation Testingライブラリ・Strykerを実戦導入してみた話
ysknsid25
7
2.6k
rootlessコンテナのすゝめ - 研究室サーバーでもできる安全なコンテナ管理
kitsuya0828
3
390
OCI Network Firewall 概要
oracle4engineer
PRO
0
4.1k
Terraform未経験の御様に対してどの ように導⼊を進めていったか
tkikuchi
2
430
データプロダクトの定義からはじめる、データコントラクト駆動なデータ基盤
chanyou0311
2
320
Featured
See All Featured
[RailsConf 2023 Opening Keynote] The Magic of Rails
eileencodes
28
9.1k
The Power of CSS Pseudo Elements
geoffreycrofte
73
5.3k
Producing Creativity
orderedlist
PRO
341
39k
Building Adaptive Systems
keathley
38
2.3k
[Rails World 2023 - Day 1 Closing Keynote] - The Magic of Rails
eileencodes
33
1.9k
Gamification - CAS2011
davidbonilla
80
5k
Fashionably flexible responsive web design (full day workshop)
malarkey
405
65k
Done Done
chrislema
181
16k
The Cost Of JavaScript in 2023
addyosmani
45
6.8k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
356
29k
GitHub's CSS Performance
jonrohan
1030
460k
Typedesign – Prime Four
hannesfritz
40
2.4k
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ࢯʹҾ͖ܧ͗ ·͢ʂ