![見出し画像](https://assets.st-note.com/production/uploads/images/28212297/rectangle_large_type_2_0e9446be10fd3a25f6fb1116d25b3263.png?width=1200)
Appleの公式ドキュメント「Testing Your Apps in Xcode」の紹介
以前、次のような記事を書きました。
Appleの公式ドキュメントもいろいろとあります。
今回はその中から「Testing Your Apps in Xcode」について紹介したいと思います。
この公式ドキュメントの内容としては次のような感じです。
- Overview
- Write a Unit Test
- Write an Integration Test
- Write a UI Test
- Write a Performance Test
本稿では、これらの内容について書かれている内容を少し紹介しつつ、私からの補足情報を追加していきます。
Overview
ここではXCTestフレームワークで利用できる4つのテストについて、そしてそれらのテストをどのように活用するとよいかについてテストピラミッドを見せつつかんたんに説明をしています。
良いテスト戦略を考える上では、これらのテストをうまく組み合わせて利用していくのが良いです。
そこで、自動テストの話題になるとよく出てくるテストピラミッドをもちいて自動テストの割合について説明しています。
これは、ユニットテスト(Unit Tests)、結合テスト(Integration Tests)、UIテスト(UI Tests)があったときに、ユニットテストをより厚くしてUIテストは一般的なユースケースぐらいにするという話です。
また、このテストピラミッドだけでなくパフォーマンステストも実装し、コードの中でパフォーマンスが重要な箇所についてもテストできるようにしましょうという話をしています。
このパフォーマンステストの話が出てくるのが特徴的かもしれません。
ただ、このXCTestで提供されているパフォーマンステストは使い勝手的になかなか難しいなと感じています。
ここでは、これらのテストの割合がどれぐらいが良いかについては述べていません。
Android側のドキュメントでは、次のような割合が書いてあります。
一般的には、小規模テスト 70%、中規模テスト 20%、大規模テスト 10% の割合でテストを作成することをおすすめします。
参考:https://developer.android.com/training/testing/fundamentals?hl=ja
また、Android側のドキュメントの図にはUnit Testsなど書いてありますが、ドキュメント上はTest Sizes(小規模、中規模、大規模)で書いています。
ここでは、Appleのドキュメントにテストピラミッドがのっているというのが大事なことのように思えます。
なお、WWDC 2017にはテストピラミッドが登場しています(もっと前から出ていたかもしれませんが、私の記憶には残っていません)。
自動テストの書き方について - Write a Unit / Integration / UI / Performance Test
「Write a Unit Test」「Write an Integration Test」「Write a UI Test」「Write a Performance Test」ではそれぞれの自動テストの実装についてかんたんに説明しています。
これらについて、どのようなことが書かれているかと、それに対する補足について次に説明をしていきます。
ユニットテスト・結合テスト
ここではテストケースの中身の実装方法として3A(Arrange、Act、Assertion)について次のように説明をしています。
- Arrange
テストで利用するオブジェクトやデータを用意します。
依存関係が複雑な場合は、スタブに置き換えてテストをしやすいようにします。protocol-oriented programmingを採用することで、依存関係をスタブに置き換えやすくなります。
- Act
Arrangeで用意したものを利用して実際にテスト対象のメソッドを呼び出します。
- Assertion
アサーションメソッドを使用して、Actでおこなった実際の結果(実測値)と、本来起こるべき値(期待値)を比較します。
なお、ドキュメントで書かれているコードは次のような感じです。
class MyAPITests : XCTestCase {
func testMyAPIWorks() {
// Arrange: create the necessary dependencies.
// Act: call my API, using the dependencies created above.
XCTAssertTrue(/* … */, "The result wasn't what I expected")
}
}
上記だと特にコードが書かれていないので分かりづらいかもしれません。
この3Aについては次の記事も参考になると思います。
また、3A以外にも「For Phase Test」などがあります。
http://xunitpatterns.com/Four%20Phase%20Test.html
(WWDC 2018であった「テストの並列化の話」の中でもsetup/teardownをちゃんと使っていい感じに分割できるようにしておきましょうなことを言っていたりします。)
この「3A」や「For Phase Test」については拙書にも書いてあります。
結合テストについては、ユニットテストとの違いは、規模であり(たとえばネットワークアクセスをしたりとか)、実装方法としてはユニットテスト同様に3Aに従いましょうという話を説明しています。
UIテスト
上述したユニットテスト、結合テストとは異なる形で動くのがXCTestでサポートしているUIテストです(なお、XCUITestと呼んでいる方もいますが、公式ではそのようにはよんではいません)。
ここでは、UIテストを作成して「アプリで重要なユーザーのタスクを実行できること」を確認しましょうと説明しています。
また、ある程度複雑なフローの場合は、XCTActivityを使用して、整理することをすすめています。
UIテストの場合だと、1つのテストケース内でいろいろなことをやってしまった結果、なんのテストをしているのかがわかりづらくなることがあります。
そこで、このXCTActivityを使ってわかりやすくすると良いです。
例えば次のように実装することができるので、よりわかりやすくなります。
func testSearch() {
XCTContext.runActivity(named: "ユーザー検索") { _ in
XCTContext.runActivity(named: "空文字で検索") { _ in
}
XCTContext.runActivity(named: "自身のユーザー名で検索") { _ in
}
}
}
また、UIテストではXcodeの機能であるRecordingを使って、操作を記録し、そのあとにアサーションを記述するという話が書かれています。
正直なところ、現在のRecording機能は不十分であると思っている(生成されたコードの問題だけでなくレコーディングできないケースがあったりと安定しているようには思えないところがあります)ので、あまりおすすめできないと思っています。
パフォーマンステスト
最後に「Write a Performance Test」としてパフォーマンステストについて言及しています。
XCTestでは、UIテストもサポートしていますが、さらにパフォーマンステストもサポートしています。
ここでは、パフォーマンステストを使って「使用メモリ」や「起動時間」などをチェックしましょうと言っています。
パフォーマンステストでは、設定した期待値の範囲より劣化していればテストを落とすことができます。
これを活用しようという話です。
ここ数年、パフォーマンス計測できる対象範囲が広がっていて、ある程度力を入れているのかもしれません。
Xcode11でXCTMetricが追加されています。
おわりに
今回のドキュメントはボリュームが少なめですが、Testingについてのドキュメントを紹介しました。
Testingについては他にもドキュメントがあります。
たとえば、既存プロジェクトにユニットテストを追加する方法について説明したドキュメントなどがあります。
プラットフォームを提供している公式がドキュメント(やサンプルコード)を用意してくれるというのは道標という意味でも非常に重要だと思っています。
すでにいろいろなドキュメントがありますし、今後これらのドキュメントはさらに充実してくれるものと思っています。
また次の機会に、なにかしらのドキュメントを紹介できればと思います。