Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
PowerMock/MockitoでCoolに テストコードを書いた話
Search
Sponsored
·
Ship Features Fearlessly
Turn features on and off without deploys. Used by thousands of Ruby developers.
→
Pakkun
December 25, 2019
Programming
110
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
PowerMock/MockitoでCoolに テストコードを書いた話
JJTC第一回 発表資料
Pakkun
December 25, 2019
More Decks by Pakkun
See All by Pakkun
Java Testing Challenge LT
junghoon
0
34
Other Decks in Programming
See All in Programming
AI主導のプログラミング学習アプリを作ってみた
econanringo
0
180
パスワード再設定メールのURLについて知っておこう
uyuki234
0
160
すこし踏み込む CancellationToken
htkym
2
1.7k
[2026-09-26]空論ジェネリックプロセス~テスト資産とAIで紡ぐ、再現可能なパフォーマンスチューニングの話~
tosite
0
270
TechTown - Creating Composable Callables in Contemporary C++
rollbear
0
130
ChromeでローカルLLM
ryu1013
0
140
Agents on Rails - Rails at Scale 2026
irinanazarova
0
560
コードで差別化できない時代の ソフトウェアエンジニアリング / Software Engineering in an Era Where Code Doesn’t Differentiate
kishida
2
180
AWS CDKのカスタムリソースでContinuum(旧Security Agent)を実装した話 | Implementing Continuum (formerly Security Agent) via AWS CDK Custom Resource
akihisaikeda
2
150
Verilogで学ぶCPU自作入門
uyuki234
8
4.1k
Apple Intelligence を用いた個人情報誤送信防止、及びユーザーリクエスト体験の改善について
yukiny
0
350
C#の現在地 進化の歴史と、AI時代の.NET Everywhere
neuecc
5
5.2k
Featured
See All Featured
Context Engineering - Making Every Token Count
addyosmani
9
1.2k
Skip the Path - Find Your Career Trail
mkilby
1
260
brightonSEO & MeasureFest 2025 - Winning Strategies for Black Friday CRO & PPC - Christian Goodrich
cargoodrich
3
870
What's in a price? How to price your products and services
michaelherold
247
13k
Fireside Chat
paigeccino
43
4.1k
Optimizing for Happiness
mojombo
378
71k
ピンチをチャンスに:未来をつくるプロダクトロードマップ #pmconf2020
aki_iinuma
128
56k
The Organizational Zoo: Understanding Human Behavior Agility Through Metaphoric Constructive Conversations (based on the works of Arthur Shelley, Ph.D)
kimpetersen
PRO
0
500
Stewardship and Sustainability of Urban and Community Forests
pwiseman
0
550
WENDY [Excerpt]
tessaabrams
14
40k
Why Our Code Smells
bkeepers
PRO
340
58k
Java REST API Framework Comparison - PWX 2021
mraible
34
9.8k
Transcript
@Pakkun PowerMock/MockitoでCoolに テストコードを書いた話
自分の経験談をベースに話して行きます。 Javaの単体テストに関する話をします。 初心者向けです。 今日話す内容
自己紹介 何故テスト コードを書くのか? 02 INTRODUCTION Why we do Testing? 01
パワーモック/モックについ て PowerMock/Mockito 04 Why Should We Use Mockito? なんでモキットなの? 03
・名前:パク ジョンフン(通称:パックン) ・勤め先:ソフトバンク株式会社(新卒入社) ・会社でやってること:#アジャイル #PCIDSS #MVNO向けエントリーAPI開発 #内製KVS開発 #アーキコンサル見習い(最近) ・趣味:バドミントン(ゴール :
-20kg) ・一言:JJTC幹事(メンバー)募集中! 01. Who Am I
“は..はい!” —先輩 “単体テストのカバレッジが低いから、 来週からカバッレッジ向上(80%)のタスク着手してくれない?” —自分
状況 ・保守開発(内製) / 社員1人+ベンダー複数人(チーム開発) ・カバレッジほぼ0%(...step数:約15万7千) ・潜んでいる闇コード(仕様書ないコードも) ・まるで秘伝のタレ(ifififififififififififififif最高!!)
“俺がやらなきゃ誰がやる” https://japaneseclass.jp/trends/about/%E7%A5%9E%E6%A7%98%E3%81%AE%E3%82%AA %E3%83%AB%E3%82%B4%E3%83%BC%E3%83%AB
約3ヶ月後... ・カバレッジ 90%越え達成! ・単体テストってなんでもかけるじゃん〜 ・なんかJUnit書くの楽しくなってきたかも
02.何故テスト コードを書くのか
上司:もうテスト完璧だよね? 自分:はい。(嘘) 上司:もう仕様100%把握したよね? 自分:はい。(嘘) 上司:もう不具合でないよね? 自分:はい。(嘘) カバレッジ向上したところで、本当に品質は向上したのか 内部秘
https://twitter.com/timeofkenzya
単体テストの カバレッジ向上 品質の向上(万能薬)
単体のカバレッジを向上させる理由 チーム開発! ・仕様書書く人/設計書書く人/ ソース書く人/テスト書く人/リリー スする人/運用する人 全員違う人かも? デグレ防止! ・過去のリリース資材の中身、何を 根拠にデグレしていないと言えま すか?
タイポ防止! ・バグの出所
単体テストの カバレッジ向上 品質の向上 単体テストの カバレッジ向上 品質の向上のきっかけ
03. Why Should We Use Mockito?
public int sum(int a, int b) { return a +
b; } <テスト対象> ...? テストしまーす Hoge.java
実際の業務のコードはこんなんじゃない! https://career-picks.com/business-yougo/sechigarai/
public void deleteLine(String word) { Line line = repository.findWord(word); //
引数で渡された単語を含む行を探す repository.delete(line); // 対象の行を削除する } <テスト対象> Q. 上記テスト対象のメソッドの「単体テスト」を作成する場合、 stubに置き換えた方が良いものは? 1. Line 2. word 3. repository 質問 LineManager.java stub:テスト用に用意した、本来の部品の代わりのもの
public void deleteLine(String word) { Line line = repository.findWord(word); //
引数で渡された単語を含む行を探す repository.delete(line); // 対象の行を削除する } <テスト対象> Q. 上記テスト対象のメソッドの「単体テスト」を作成する場合、 stubに置き換えた方が良いものは? 1. Line 2. word 3. repository 答え 僕には時間がないんだ!「 repository」は他でテストしてくれ! deleteLineのメソッド単体の挙動をテストすることが大事! LineManager.java
public void deleteLine(String word) { Line line = repository.findWord(word); //
引数で渡された単語を含む行を探す repository.delete(line); // 対象の行を削除する } <テスト対象> じゃあどうやってStubにすんの <テストコード(一部)> Line line = new Line(); // 適当な行をnewして repositoryStub.setLineToFind(line); // 作ったスタブの戻り値をセット lineManager.setRepository(repositoryStub); // repositoryをStubに置き換える lineManager.deleteLine("hoge"); // テスト対象のコードを実行 repositoryStub.verifyLineDeleted(line); // テスト対象のコードが「行削除」のコードを呼び出しているか 確認する 自分で「 RepositoryStub」を作るしかないよね。。。 (作ったとして) LineManager.java LineManagerTest.java
・Stub-Run-Assertの順にテストしている。 ・「verifyLineDeleted」メソッドで、 対象のコードがきちんと呼び出されているか確認。 ・Stubは検証の対象ではない。 repositoryStub.setLineToFind(line); lineManager.deleteLine("hoge"); repositoryStub.verifyLineDeleted(line); テストの流れ(頭の中整理) LineManagerTest.java
・テスト対象クラス(主人公)の下位クラス(ガヤ)の定義を ラップできるオブジェクト。 →テストする人の都合のいいように、 余計に出てくるクラス(ガヤ)の定義を上書きしちゃえるってこと。 さっき手でやってたことを楽にしてくれそうだね モックの登場
モックライブラリの種類 ・Mockito ・PowerMock ・EasyMock ・JMockito ・jMock ・etc..
モックライブラリの種類 ・Mockito ・PowerMock ・EasyMock ・JMockito ・jMock ・etc.. まずこれつかってみよう
Mockito を選んだ理由 https://trends.google.co.jp/trends/? geo=JP 1. 良く使われてるじゃん #ググりやすそう(大事) 2. 他のライブラリと比べ コード量が少ないじゃん
#時間がない! 3. Stub-Run-Assert #考え方が自分と良く会う # 「Mocks aren't Stubs」- Martin Fowler 氏 に沿っており、TDDの思考と逆行しない。 ThoughtWorks社の開発者もMockito使ってるらしい。 (TDDについてはまた次回 )
“なんか、良さそうだから Mockito使って書きまーす” “private/static/final/innerClass とかは Mockitoじゃ無理だからPowerMock つーかお”
04. PowerMock/Mockito
Mockitoで書くとこんな感じ repositoryStub.setLineToFind(line); lineManager.deleteLine("hoge"); repositoryStub.verifyLineDeleted(line); when(mockRepository.findLine("hoge")).thenReturn(line); lineManager.deleteLine("hoge"); verify(mockRepository).delete(line); ・手作りStub ・Stubの振る舞いを一式用意しておく ・前段で生成しておくだけ
・使うときに振る舞いを定義する
PowerMockはMockitoができること全般は もちろん、Mockitoでは対応できない ハードケースにも対応できるが、処理が重い とはとは Mockitoではpublicクラス/メソッドを モック化し、メソッド呼出し時に処理を 無効にしたり、特定の戻り値を返したりといった一般 的な使い方はできるが、private/static/finalメソッドに は対応できない
Mockito/PowerMockのモックオブジェクトの種類 ① mockメソッドのモックオブジェクト - 基本的にモックの全メソッドが無効となる - テストに都合の良い値を返すようにメソッド定義を上書きする必要がある ② spyメソッドのモックオブジェクト -
元の処理が実行される - 挙動を変更したいメソッドに対して、定義を上書きする必要がある 一部は元通りの処理、一部は挙動を変更したい場合にspyを使う それ以外全て普通のmockメソッドを利用しましょう。
実装方法(Maven利用) 1. dependencyをpomに追加 <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-api-easymock</artifactId> <version>----</version> </dependency> <dependency> <groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId> <version>----</version> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-core</artifactId> <version>----</version> </dependency> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>----</version> </dependency>
2. モジュールインポート 3. runner指定(テストクラスに下記のアノテーションを設定) ## Mockitoのみの場合 @RunWith(MockitoJUnitRunner.class) public class XxxTest
{…} ## PowerMockを使う場合 @RunWith(PowerMockRunner.class) @PrepareForTest({Hoge.class, Fuga.class}) // PowerMockが扱うクラス public class XxxTest {…} import static org.mockito.ArgumentMatchers.*; import org.junit.runner.RunWith; import org.mockito.junit.MockitoJUnitRunner; import org.powermock.modules.junit4.PowerMockRunner; import org.mockito.Mock; import org.mockito.Spy;
4. モックオブジェクトの生成(Mockito) アノテーションによる生成(クラス変数にのみ使用可能) メソッドによる生成(クラス変数にのみ使用可能) @Mock Hoge hogeMock; @Spy Fuga fugaSpy;
Hoge hogeMock = Mockito.mock(Hoge.class); Fuga fugaSpy = Mockito.spy(Fuga.class); Piyo piyoSpy = Mockito.spy(new Piyo(arg0, arg1));
4. モックオブジェクトの生成(PowerMock) アノテーションによる生成(クラス変数にのみ使用可能) メソッドによる生成(クラス変数にのみ使用可能) なし FinalHoge hogeMock = PowerMockito.mock(FinalHoge.class); //
final class Piyo piyoSpy = PowerMockito.spy(new Piyo(arg0, arg1)); // private method を扱う PowerMockito.mockStatic(StaticHoge.class); // static method を扱う
5. 挙動の上書き 戻り値を上書き 特定のメソッドを無効化する 特定のメソッドを無効化する (Power)Mockito.when(hogeMock.getSomething(anyString())).thenReturn(“hoge”); (Power)Mockito.doReturn(myObj).when(piyoSpy).getSomething(); PowerMockito.when(StaticHoge.get()).thenReturn(some Object); Mockito.doNothing().when(hogeSpy).doSomething(any(OtherClass.class));
PowerMockito.doNothing().when(StaticHoge.class, “method name”); (Power)Mockito.doThrow(new Exception()).when(mySpy).doSomething();
実際に書いてみよう! パターン:private メソッドのモック化が必要な場合 public class Hoge { public void doSomething()
{ ... String key = ...; String value = this.getProperty(key); ... } private String getProperty(String key) { ... return xxx; } } クラス定義
@RunWith(PowerMockRunner.class) @PrepareForTest({Hoge.class}) public class HogeTest { public void testDoSomething() {
Hoge h = PowerMockito.spy(new Hoge()); PowerMockito.doReturn(“dummy value”).when(h, “getProperty”, anyString()); h.doSomething(); ... assertThat(...); } } テストロジック
・引数指定でnullの扱いは要注意 ・MockitoとPowerMockの使い分け #qiitaにいい感じのまとめがありました。 https://qiita.com/euledge/items/a224777c15ae7145114a その他注意事項
まとめ # 初心者向け # どっかでまとめてテストはNG! # Mockが多くなると...地獄 #次回のネタは
ご清聴ありがとうございました。
APPENDIX
・「Mocks aren't Stubs」- Martin Fowler 氏 https://martinfowler.com/articles/mocksArentStubs.html
Expect-Run-Verify 他の模擬Objのテストフレームワークはどうだったか(Mockito以外) // expect Line line = new Line(); expect(mockRepository.findLine("foo")).andReturn(line);
mockRepository.delete(line);←検証すべきコード // run replay(mockRepository); lineManager.deleteByWordLists("foo");←テストの実行 // verify verify(mockRepository); EasyMock
EOF