悩んだこと
最近、[[GraphQL]]の query のテストでどう書こうかとても悩んだので備忘録として残しておきます。 雑ですが下記のようなレスポンスを返す query があったとします。 query としては下記が正しく返ってきているかをテストできれば問題ないとします。
{
"data": {
"testQuery": {
"labels": [
"ラベル1",
"ラベル2",
"ラベル3",
],
"datasets": [
{
"label": "項目A",
"data": [
1,
2,
3
]
},
{
"label": "項目B",
"data": [
1,
2,
3
]
},
...
]
}
}
}
その場合、本来はデータを準備して、そのデータのときに、こういうレスポンスが返ってきているであろうということを確認するテストを書けば良いのですが、細かい仕様がたくさんありこのレスポンスを返すまでに内部では private メソッド内で細かい処理が行われていました。
そのため、次の点で悩みました。 - ① 何かしらの改修でテストが落ちたときにどこの仕様で落ちたか調査に時間がかかる。 - ② 複雑なロジックのため、レスポンスのテストだけだと不安が残る。 特に、漠然とした不安が気になりどうすればいいのか悩みました。
考えたこと
色々調べていたところ、private メソッドをわざわざテストするのはアンチパターンという記事を見つけました。
- private メソッドをわざわざテストしている これについてはコード例までは載せませんでしたが、これもよくあるやらかしです。public メソッドは既にテストしていますし、その結果は private メソッドから生み出されたのですから、private メソッドをテストする必要などありません。どうしても private メソッドをテストしたいというのであれば、まずコードの方をもっと小さなクラスに分割してから、それらを個別にテストすることを検討しましょう。このような事態を避ける最良の方法は、メソッドを設計するときに「単一責任の原則」を用いることです。 https://techracho.bpsinc.jp/hachi8833/2018_04_19/55015 ここに書いてある通りだと思いました! 細かい仕様については private メソッドでやっていますが、その最終結果は public メソッドの結果に表れますし、public メソッド自体はテストしているので、二重にテストをやっているみたいなことになると思います。 自分がやろうとしていることはアンチパターンだと分かったのですが、時間が経った後に複雑なロジックを思い出せるかも不安があったので、どうやってこの不安を解消しようか考えました。
結論
調べながら、Kent Beck さんという方のお言葉(正確なソースが不明なので間違っていたらすみません…)で「不安が退屈に変わるまでテストしよう」というお言葉があることを知りました。 本来は重複するという点でアンチパターンだと思いますが、後で不安になるのでコメント入れて仕様的な観点のテストも追加して対応しました。
context 'Aのとき' do
# queryのレスポンスのテストと重複しますが、仕様を明確にするために追加
it '細かい仕様のテスト1' do
# 仕様のテストを書く
end
# queryのレスポンスのテストと重複しますが、仕様を明確にするために追加
it '細かい仕様のテスト2' do
# 仕様のテストを書く
end
it 'queryから正しいレスポンスが返ること' do
expect(result).to eq(
{
"testQuery" => {
"labels" => labels,
"datasets" => datasets
}
}
)
end
end
2022/03/22 追記
上記のテストに対して、同じデータを使い回していたのですが RSpec では it のたびに let を実行し、データを都度作成するためオーバーヘッドが発生していました。そのため、仕様部分のテストは無駄にデータを作ることになっていたため最終的には削除することにしました。今後同じようなケースが出てきたときは仕様ごとに適切なデータを準備してそれに対してテストを書くようにしようと思いました。