各テストについて、arrange-act-assert構造に従うようにしてください。
- オブジェクトなどを配置し、既知の状態(テストフィクスチャ)にします。場合によっては、このフェーズには、自分が実際に自分がいると思っている状態にあることを示すアサートが含まれます。
- 行為、つまり、テストしている動作を実行します。
- 期待どおりの結果が得られたことを表明します。
テストでは、最初に既知の状態を作成する必要がないため、単独では意味がありません。
また、単体テストは必ずしも単一のメソッドのみをテストするわけではありません。単体テストはユニットをテストする必要があります。通常、このユニットはクラスです。のようないくつかの方法はget()
、他のものとの組み合わせでのみ意味があります。
特に動的言語では、ゲッターとセッターのテストは賢明です(実際に存在することを確認するためだけです)。ゲッターをテストするには、最初に既知の値を指定する必要があります。これは、コンストラクターまたはセッターを通じて発生する可能性があります。または別の見方をすると:ゲッターのテストは、セッターとコンストラクターのテストでは暗黙的です。そしてセッター、それは常にを返しtrue
ますか、それとも値が変更されたときだけですか?これにより、次のテスト(疑似コード)が発生する可能性があります。
describe Api:
it has a default value:
// arrange
api = new Api()
// act & assert
assert api.get() === expected default value
it can take custom values:
// arrange & act
api = new Api(42)
// act & assert
assert api.get() === 42
describe set:
it can set new values:
// arrange
api = new Api(7)
// act
ok = api.set(13)
// assert
assert ok === true:
assert api.get() === 13
it returns false when value is unchanged:
// arrange
api = new Api(57)
// act
ok = api.set(57)
// assert
assert ok === false
assert api.get() === 57
以前のテストの状態を再利用すると、テストが非常に脆弱になります。テストを並べ替えたり、テストの正確な値を変更したりすると、明らかに関連のないテストが失敗する可能性があります。特定の状態を想定すると、実際に失敗するはずのテストに合格した場合に、バグを隠すこともできます。これを防ぐために、一部のテストランナーには、テストケースをランダムな順序で実行するオプションがあります。
ただし、前のテストで提供された状態を再利用する場合があります。特に、テストフィクスチャの作成に時間がかかる場合、多くのテストケースを1つのテストスイートにまとめますか。これらのテストは脆弱ですが、より迅速かつ頻繁に実行できるため、今でも価値があるかもしれません。実際には、テストに手動コンポーネントが含まれる場合、大規模なデータベースが必要な場合、または状態マシンをテストする場合は、テストを組み合わせることが望ましいです。
myApi
は、インスタンス化されたオブジェクトであるとしましょう。myApi
各単体テストでインスタンス化する必要がありますか?または、テスト間でそれを再利用すると、テストで偽陽性などが発生する可能性があります。そうです、私の例は、簡略化されたゲッター/セッターですが、実際には明らかにはるかに複雑になります。