1 of 12

Android: テストメソッドの命名規則について考えてみた

佐藤 隼 (@stsn_jp)

2 of 12

目次

  1. このテーマを選んだ背景
  2. テストを構築する4つの要素
  3. 初期 => 中期 => 現在期 と, どのようにテストコードが変わっていったのか
  4. まとめ

3 of 12

背景: そもそもの問題点/出発点

Androidでテストを書き始めたは良いものの, テストコードがカオスになってきた...

可読性が低い, そもそも何のテストをしているか分からない, 粒度が荒い, テストが落ちた時に修正ではなく, 削除したくなる

4 of 12

背景: そもそもの問題点/出発点

テストコードを書くと決めたら, 負債にならないようにする必要がある!!

テストメソッドの命名規則をしっかりとすれば, ある程度解決できると思い, ルール作りをしました.

5 of 12

一般的なテストの構成要素

  1. 事前準備(setup)
  2. 実行(exercise)
  3. 宣言(assertion)
  4. 後処理(teardown)

で構成される.

これらが組み合わせることで, 1つのテストが構築される

public class HTTPConnectionTest {� HTTPConnection httpConnection;� @Before public void setup() {

// 事前準備(setup)

httpConnection = new HTTPConnection();}

@Test public void execute() {// 事前準備(setup)� Request validRequest = new Request("http://valid-url.com")// 実行(exercise)� Response response = httpConnection.execute(validRequest);// 宣言(assertion)� assertThat(response.isOk()).isTrue();�� // 事前準備(setup)� Request inValidRequest = new Request("http://invalid-url.com")// 実行(exercise)� response = httpConnection.execute(inValidRequest);// 宣言(assertion)� assertThat(response.isOk()).isFalse();}}

6 of 12

テストexecuteの

粒度を考える

HTTPConnectionクラスのexecute関数にはvalid/invalidの2パターンがある

右の例だと, valid/invalidが1つのテストにまとまっている(1つのテストの中で複数のことを宣言してはいけない)

public class HTTPConnectionTest {� HTTPConnection httpConnection;� @Before public void setup() {� httpConnection = new HTTPConnection();}

@Test public void execute() {// 事前準備(setup)� Request validRequest = new Request("http://valid-url.com")// 実行(exercise)� Response response = httpConnection.execute(validRequest);// 宣言(assertion)� assertThat(response.isOk()).isTrue();�� // 事前準備(setup)� Request inValidRequest = new Request("http://invalid-url.com")// 実行(exercise)� response = httpConnection.execute(inValidRequest);// 宣言(assertion)� assertThat(response.isOk()).isFalse();}}

7 of 12

テストを分割

valid/invalidを右のように分割する

これで, 1つのことを宣言するようになった

しかし, execute_ok, execute_ngだと, どのような前提条件(引数)の場合に, ok, ngになるのか分からない

public class HTTPConnectionTest {� HTTPConnection httpConnection;� @Before public void setup() {� httpConnection = new HTTPConnection();}

@Test public void execute_ok() {� Request validRequest = new Request("http://valid-url.com")� Response response = httpConnection.execute(validRequest);� assertThat(response.isOk()).isTrue();� }

@Test public void execute_ng() {� Request inValidRequest = new Request("http://invalid-url.com")� Response response = httpConnection.execute(inValidRequest);� assertThat(response.isOk()).isFalse();}}

8 of 12

前提条件を含める

execute_ok_200URL, execute_ng_404URLとし, 前提条件もメソッド名に含める

「5xx系のテストやってないじゃないか!」 などのテスト漏れを防ぐことが出来る

public class HTTPConnectionTest {� HTTPConnection httpConnection;� @Before public void setup() {� httpConnection = new HTTPConnection();}

@Test public void execute_ok_200URL() {� Request validRequest = new Request("http://valid-url.com")� Response response = httpConnection.execute(validRequest);� assertThat(response.isOk()).isTrue();� }

@Test public void execute_ng_404URL() {� Request inValidRequest = new Request("http://invalid-url.com")� Response response = httpConnection.execute(inValidRequest);� assertThat(response.isOk()).isFalse();}}

9 of 12

こうすることのメリット

粒度が保たれる

前提条件がメソッド名に含まれるため, 他のデータを使うようなテストを書けない (e.g. execute_ok_200URLの中に, 3xx系のテストは混入しない)

テストが失敗した時の原因究明/修正がしやすくなる

名前から推測, 1つのテストで1つのことをすることが強制されるため

10 of 12

一般化すると

テスト対象メソッド名_期待される振る舞い_前提条件

execute ok 200URL

11 of 12

まとめ

テストを負債化しないため, テスト全体のルール作りは必須

命名規則, 粒度, ツール, などなど最低限のルールを決める

makeコマンドや, gradleコマンドでbuildするときは, テストも走らせるようにすると忘れないで良い

Android Studioのcoverage reportの機能は非常に便利

12 of 12

Thanks!

佐藤 隼(サトウ シュン)

twitter and contact:� @stsn_jp

Skills:

Android, Python, AWS,

SQL, Git, etc...