LoginSignup
1
1

More than 5 years have passed since last update.

GAE/Java8試行(その3:「Javaアプリテストコード解説」)

Last updated at Posted at 2018-10-05

お題

前々回、GAE用のJava8アプリをMaven自動生成して、前回は主な修正対象のファイルについて説明。
今回から、とりあえずDatastoreへのアクセスロジック入れていこうかと思ったけど、その前にテストコードについても触れておこう。
一応、テストファーストで進めていく予定なので。

GAE試行Index

開発環境

# OS

$ cat /etc/os-release 
NAME="Ubuntu"
VERSION="17.10 (Artful Aardvark)"

# Java

$ java -version
java version "1.8.0_181"
Java(TM) SE Runtime Environment (build 1.8.0_181-b13)
Java HotSpot(TM) 64-Bit Server VM (build 25.181-b13, mixed mode)

# IDE

みんな大好きIntelliJ IDEA

解説(というか自分自身のおさらい)

自動生成されたテストコードは「HelloAppEngineTest.java」

$ tree ※必要な部分だけ抜粋
.
└── sky0621
    ├── pom.xml
    └── src
         └── test
             └── java
                 └── com
                     └── example
                         └── sky0621
                             └── HelloAppEngineTest.java

ソースコードの全量は↓に。
https://github.com/sky0621/java-webapi-for-gae-study/blob/1a9d408da2a670ac2d61416d6ec964ae4306c8b8/sky0621/src/test/java/com/example/sky0621/HelloAppEngineTest.java

以降、説明に必要な部分を抜粋しつつまとめる。

■JUnit4とmochito

@RunWith(JUnit4.class)
public class HelloAppEngineTest {
  〜省略
  @Mock private HttpServletRequest mockRequest;
  @Mock private HttpServletResponse mockResponse;
  〜省略

App Engine用のMavenプロジェクトを自動生成すると、「pom.xml」で以下のVersionで定義される。

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>
    <dependency>
      <groupId>org.mockito</groupId>
      <artifactId>mockito-all</artifactId>
      <version>1.10.19</version>
      <scope>test</scope>
    </dependency>

JUnitは、最新という意味では「JUnit5」が出てるけど、ここでは大人しく、指定されたバージョンを使う。
Mockitoは、Javaのテストコードでモックを使うときの定番。
モック化したいオブジェクトの頭に「@Mock」アノテーションを付けるだけなので簡単。

■テストケース実行前処理

  @Before
  public void setUp() throws Exception {
  〜省略
  }

@Before」付加により、各テストケース実行前に行うべき処理を定義できる。

    when(mockRequest.getRequestURI()).thenReturn(FAKE_URL);
    when(mockResponse.getWriter()).thenReturn(new PrintWriter(responseWriter));

先ほど見た「@Mock」アノテーションを付けたオブジェクトは、こうすることで挙動を操作できる。
(説明なくても、なんとなく意味はわかると思う。)

■LocalServiceTestHelper

import com.google.appengine.tools.development.testing.LocalServiceTestHelper;
  〜省略
  private final LocalServiceTestHelper helper = new LocalServiceTestHelper();
  〜省略
  @Before
  public void setUp() throws Exception {
    helper.setUp();
   〜省略
  }

LocalServiceTestHelperを各テストケース実行前にセットアップしておくことで、appengineのライブラリを使ってGAEからDatastoreないしMemcacheといったサービスにアクセス(=通信を伴う)する際に接続先をスタブにしてくれる(=通信レス)。
こうすることで、通信先がある環境かどうかに依存しないテストコードが書ける。
(テストコードは、どこでもなんどやっても同じ結果になる冪等性が大事)

■テストケース実行後処理

  @After public void tearDown() {
    helper.tearDown();
  }

@After」付加により、各テストケース実行後に行うべき処理を定義できる。
ここでは、セットアップしたLocalServiceTestHelperの後始末を行う。

■テストケース

import static com.google.common.truth.Truth.assertThat;
  〜省略
  @Mock private HttpServletRequest mockRequest;
  @Mock private HttpServletResponse mockResponse;
  private StringWriter responseWriter;
  private HelloAppEngine servletUnderTest;
  〜省略
  @Test
  public void doGet_writesResponse() throws Exception {
    servletUnderTest.doGet(mockRequest, mockResponse);

    // We expect our hello world response.
    assertThat(responseWriter.toString())
        .named("HelloAppEngine response")
        .contains("Hello App Engine - Standard ");
  }

モックを渡して、テスト対象である「HelloAppEngine#doGet」のテストを行う。
結果の検証には「assertThat」を使う。
↑はJUnitのものではなくGoogleが提供しているパッケージを使う。

まとめ

ひとまず(当然のことながら)自動生成されたテストコードの時点では冪等性のあるものになっている。
ここを崩さないようにしつつ、テスタブルなプロダクトコードを書いていく。
次こそは、Datastoreアクセスコードを書こう。。。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1