単体テストで画面遷移もやっちゃおう、と思って格闘したときの覚書です。
アプリの起動はテスト実行時一回のみ行われる
テスト対象のアプリは、テストの実行時一回のみ行われます。
@testable import app
つまりAppDelegateは初回のテストケースで一度だけ走ります。
各テストケースでは走リません。
デフォルトのテストケースの実行順序はクラス名順 -> テストケースメソッド名順
テストケースの実行順序は名前の順になります。
個人的にはクラスの中で、上から下に舐めていって欲しい気持ちがあったのですが、それは仕様みたいです。
テストケースの実行をランダムにするオプションはあるんですが、デフォルトは名前順。
基本テストケースの実行順序に依存するようなテストコードを書くな、というのはあるんでしょうけど、
何らか制約が生じてしまうときは、名前で縛るしかないのかなあという感じです。
たとえばtest_1_何かの確認
、test_2_何かの確認
みたいな。
あるテストケースでアプリに加えた変更は次のテストケースに引き継がれる
テストケースのたびにアプリの状態はイニシャルしてしまって構わないのですが、
多分パフォーマンスの問題だと思うんですが、イニシャルはされず、次に引き継がれます。
別にModelクラスならそんなに困ることはないんですが、UIが関わるクラスだと結構キツイです。
tearDown()でちゃんと後始末して、常にきれいな状態で次のテストケースに引き継げるように記述できれば良いんですが、
テストのことをあまり考えずにつくったアプリだとキツイときもあって、みんなどうしてんだろうなあって思いました。
Class単位にsetup()/tearDown()ができる
これは明示的に書かれていないということはなく、
テストの本読むとXCTestのライフサイクルとしてちゃんと書かれていますが、
サンプルコートの中になくて、使わないので盲点になっていました。
XCTestCaseのclassメソッドsetup()/tearDown()はテストclassに対して一回。
通常のsetup()/tearDown()はテストケースに対して一回。
何を言っているのかというと、
class override func setUp() {
<#code#>
}
override func setUp() {
// Put setup code here. This method is called before the invocation of each test method in the class.
}
override func tearDown() {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}
class override func tearDown() {
<#code#>
}
この一番上と一番下のクラスメソッドはクラス中で一回だけ、
二番目、三番目のメソッドは各テストケースごとに実行されます。
僕は画面遷移する前にアプリが持っている情報をテスト前に退避して、
テストでは仮のデータ突っ込んでめちゃくちゃにして、テスト後は退避したものをきれいに戻す、みたいな書き方をしようとしたんですが、
使ってみたらクラスメソッドだと子クラスの中に書いた変数が使えないので、退避先がなくて実現しませんでした。
本気であまり使い所ないかもしれませんね……
UIテストだとアプリ自体の起動・終了が制御できる
アプリの状態をイニシャルできないというのは、UIテストだったら、アプリの起動・終了が制御できるので、多少は良いかなと思います。
XCUIApplication().launch()
画面遷移ならむしろUIテストで書くのが筋なんですかね?