テスト

概要

プログラムをきちんと書いたつもりでも、本当に意図通りに書けているとは限らない。
そのため、プログラムが意図通り動作するかを、実際に動かして確認する必要がある。

ただし、入力を闇雲に与えるだけでは、まともな確認にはならない。
どのような入力を試すべきか、何を確認しているのかを考えながらテストする必要がある。

テストの注意点

どんな入力例を与える場合でも、実行前に以下の $2$ つを意識する。

これらのどちらかが欠けると、プログラムが変な動作をしていても見落としやすい。
「正常動作、ヨシ!」としてしまわないように注意すること。

テストの種類

サンプルテスト

問題文にある入力例を実際に試し、サンプル出力と一致するか確認する。
最初に必ず行う基本的なテストであり、どんな問題でも最低限行うべきテストである。

ブラウザや補助ツールを使うと、全入力例に対するテストを楽にできる場合がある。
例えば、AtCoder Easy Test などを使うと、サンプルテストをまとめて実行できる。

注意点として、Yesyes のような細かい表記ミスは見落としがちなので丁寧に確認すること。
また、正解となる出力が複数ある場合は、出力例と一致しない結果になっても問題ない場合がある。
その場合は、自分の出力が問題文の条件を満たしているかを丁寧に確認すること。

誤答しやすい入力を意図的に省いてある問題もある。
このテストが通ったからと言って過信は禁物。
特に、非常に長い数列の入力などが入力例に掲載されていることはまずないので、注意が必要。

自作テスト

自分で入力を作り、手計算した答えとプログラムの出力を比較する。
問題で与えられている入力例は、誤答しやすい入力を意図的に載せていない場合がある。

「公式入力例には存在しないけど、こういうケースは何か起こりそう」という入力例を自作する。
実行前に、手計算で正しい出力を求めておくこと。

コーナーケースのテスト

特殊な入力のときに特殊な対応をしなければならない場合に、それができているかを確認するテスト。
提出前にやるのはもちろん、提出結果がわずか数ケースだけ WA だったときにも再度確認するとよい。

詳しくは、コーナーケースのページで扱う。

境界値テスト

条件が切り替わる直前直後の値を試すテスト。

例えば、「$N$ は $1$ 以上 $500$ 以下の整数で、その各桁の数の合計を求める」という場合。
この場合は、次のような値を試す。

本来は、$0$ や $501$ のような制約外入力を検出できるかのテストも考えられる。
ただし、競技プログラミングでは、制約外入力への対応は省略してよい。

境界値テストでは、if 文の不等号間違いや、ループの回数ミスといった論理エラーを検出しやすい。
また、全く気づいていなかったコーナーケースが、偶然検出できることもある。

一方で、ある程度処理を行った先の条件分岐のテストは難しい。
一般に、処理途中の値が境界値ぴったりになる入力を作るのが大変なことが多い。
特に、答えが最大になるケースは、理論的に探すのが難しい場合もある。

場合分けのテスト

if 文や考察上の場合分けがあるなら、それぞれの場合に対応する入力を試す。
サンプルテストが片方の分岐だけしか通らず、提出後にもう片方の分岐で WA になることがある。

複数の入力例で、コード上の全ての分岐を通るように入力例を取りそろえること。
これを分岐網羅という。

&& を使っている場合は、それぞれの条件が $1$ つだけ false になる例を用意するとよい。
|| を使っている場合は、逆に $1$ つだけ true になる例を用意するとよい。
これは、条件網羅を少し簡略化したものと考えられる。

ストレステスト

大量のデータを処理させて、何か異常が起きないか試してみるテスト。
ここでは、巨大な数列などの入力に対して TLE しないかどうかのテストを指す。

入力例に絶対に存在しないテストなので、やる価値は高い。
ただし、入力データを用意するのが大変。

なお、下の項目のランダムテストを、ストレステストと呼ぶ人もいる。

ランダムテスト

小さい入力をランダムに大量に作り、愚直解と本解の出力を比較する。
手で見つけにくいミスを発見できることがある。

ランダムテストを行うには、次のものを用意する必要がある。

準備には時間がかかる。
しかし、解法に不安がある場合や、細かい場合分けが多い場合には強力な確認方法になる。

使い方の応用

提出前に最低限確認する

提出前には、少なくともサンプルテストを全て通す。
そのうえで、気になる自作テストや境界値テストを追加する。

特に、サンプルにない分岐、最小値、最大値、空に近い状態、全て同じ値、などは確認候補になる。

提出後の結果から追加で確認する

ほとんど AC して、少数ケースだけ WA になった場合は、コーナーケースや境界値を疑う。
全体的に WA している場合は、入出力形式、方針そのもの、添字のずれなどを疑う。

計算量的には間に合うはずなのに TLE する場合は、無限ループや想定外の重い処理を疑う。
大量データのストレステストや、cerr による途中経過の確認が役立つことがある。

注意点

サンプルが通っても正しいとは限らない

サンプルテストは最初に行うべきだが、十分条件ではない。
サンプルにない入力で WA になることはよくある。

サンプルが通った後も、境界値、場合分け、コーナーケースを確認すること。

正しい出力を先に考える

自作テストを作る場合、実行前に正しい出力を考えること。
プログラムを実行してから「それっぽい出力だから合っている」と判断すると、誤答を見落としやすい。

制約外入力は基本的に考えなくてよい

競技プログラミングでは、問題文の制約を満たす入力だけが与えられる。
そのため、制約外入力に対するエラー処理は、基本的には書かなくてよい。

ただし、境界値を考えるときに、制約の下限・上限を意識することは重要である。

関連知識

エラー

テストで出力や挙動がおかしい場合、エラーの種類を切り分けて原因を探す。
コンパイルエラー、実行時エラー、論理エラーで確認する場所が変わる。

コーナーケース

特殊な入力だけ別処理が必要な問題では、コーナーケースのテストが重要になる。
ほとんど AC して一部だけ WA になる場合は、コーナーケースを疑う。

入出力

入力の個数や順番がずれていると、サンプルテストや自作テストで想定と違う結果になる。
まずは入力形式と出力形式が問題文に合っているか確認する。

if分岐

場合分けのテストでは、if文の各分岐を通る入力を用意する。
不等号、&&|| の条件ミスは、境界値テストや場合分けのテストで見つけやすい。

計算量の見積もり

ストレステストでは、大きな入力を処理させて、計算量の見積もりが正しいかを確認する。
ただし、本当に間に合うかは、まず理論上の計算量で判断する。