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
740
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
130
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
620
I/O 2017 Short Report
srym
0
310
Other Decks in Technology
See All in Technology
事業を差別化する技術を生み出す技術
pyama86
2
400
ディスプレイ広告(Yahoo!広告・LINE広告)におけるバックエンド開発
lycorptech_jp
PRO
0
490
クラウド食堂とは?
hiyanger
0
120
自分だけの仮想クラスタを高速かつ効率的に作る kubefork
donkomura
0
110
EMConf JP 2025 懇親会LT / EMConf JP 2025 social gathering
sugamasao
2
200
【5分でわかる】セーフィー エンジニア向け会社紹介
safie_recruit
0
19k
LINE NEWSにおけるバックエンド開発
lycorptech_jp
PRO
0
320
Amazon Aurora のバージョンアップ手法について
smt7174
2
180
実は強い 非ViTな画像認識モデル
tattaka
3
1.4k
DeepSeekとは?何がいいの? - Databricksと学ぶDeepSeek! 〜これからのLLMに備えよ!〜
taka_aki
1
160
Change Managerを活用して本番環境へのセキュアなGUIアクセスを統制する / Control Secure GUI Access to the Production Environment with Change Manager
yuj1osm
0
110
MIMEと文字コードの闇
hirachan
2
1.4k
Featured
See All Featured
Visualizing Your Data: Incorporating Mongo into Loggly Infrastructure
mongodb
45
9.4k
Making the Leap to Tech Lead
cromwellryan
133
9.1k
How To Stay Up To Date on Web Technology
chriscoyier
790
250k
Agile that works and the tools we love
rasmusluckow
328
21k
The Illustrated Children's Guide to Kubernetes
chrisshort
48
49k
Navigating Team Friction
lara
183
15k
個人開発の失敗を避けるイケてる考え方 / tips for indie hackers
panda_program
100
18k
Optimizing for Happiness
mojombo
377
70k
Side Projects
sachag
452
42k
Building a Scalable Design System with Sketch
lauravandoore
461
33k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
53k
Mobile First: as difficult as doing things right
swwweet
223
9.5k
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ࢯʹҾ͖ܧ͗ ·͢ʂ