単体テストの命名規則を変更する必要がありますか?
-
06-07-2019 - |
質問
現在、単体テストには単純な規則を使用しています。「EmployeeReader」という名前のクラスがある場合は、「EmployeeReader.Tests」という名前のテスト クラスを作成します。次に、テスト クラス内にクラスのすべてのテストを次のような名前で作成します。
- Reading_Valid_Employee_Data_Correctly_Generates_Employee_Object
- Reading_Missing_Employee_Data_Throws_Invalid_Employee_ID_Exception
等々。
私は最近、あることについて読んでいます 異なる種類の命名規則 BDD で使用されます。この名前の読みやすさが気に入っています。最終的には次のようなテストのリストになります。
- When_Reading_Valid_Employee (フィクスチャ)
- Employee_Object_Is_Generated (メソッド)
- Employee_Has_Correct_ID (メソッド)
- When_Reading_Missing_Employee (フィクスチャ)
- An_Invalid_Employee_ID_Exception_Is_Thrown (メソッド)
等々。
両方のスタイルの命名を使用した人はいますか?アドバイス、メリット、デメリット、注意点などあれば教えてください。次のプロジェクトに切り替えるかどうかを決めるのに役立ちますか?
解決
2 番目の例 (クラスごとに 1 つではなく、論理「タスク」ごとにフィクスチャがある) には、タスクごとに異なる SetUp ロジックと TearDown ロジックを使用できるという利点があり、その結果、個々のテスト メソッドが簡素化され、読みやすくなります。
どちらかを標準として決める必要はありません。各クラスでテストする必要がある異なる「タスク」の数に応じて、両方を組み合わせて使用します。
他のヒント
使用している命名規則は次のとおりです。
functionName_shouldDoThis_whenThisIsTheSituation
たとえば、これらはスタックの「ポップ」関数のテスト名になります
pop_shouldThrowEmptyStackException_whenTheStackIsEmpty
pop_shouldReturnTheObjectOnTheTopOfTheStack_whenThereIsAnObjectOnTheStack
2番目の方が良いと思うのは、長い行がコードを読みにくくしたり、ざっと読みにくくするので、ユニットテストが他の人にとって読みやすくなるからです。それでもテストの実行内容にあいまいさがある場合は、コメントを追加してこれを明確にすることができます。
参照する2番目の命名規則の背後にある推論の一部は、テストと動作仕様を同時に作成していることです。あなたは物事が起こっているコンテキストを確立し、そのコンテキスト内で実際に何をすべきかを確立します。 (私の経験では、観察/テスト方法はしばしば" should _、&;で始まるため、標準の" When_the_invoicing_system_is_told_to_email_the_client、"" should_initiate_connection_to_mail_server"形式を取得します。)
テストフィクスチャを反映し、適切にフォーマットされたHTML仕様シートを出力し、アンダースコアを削除するツールがあります。最終的に、実際のコードと同期した人間が読めるドキュメントになります(テストカバレッジを高く正確に保つ限り)。
作業しているストーリー/機能/サブシステムに応じて、これらの仕様は、特にアジャイルとBDDの中心である検証とフィードバックのために、プログラマー以外の利害関係者に示され、理解されます。
2番目の方法を使用します。これは、ソフトウェアが何をすべきかを説明するのに非常に役立ちます。また、ネストされたクラスを使用して、より詳細なコンテキストを記述します。
本質的に、テストクラスはネスト可能なコンテキストであり、メソッドはすべて1行のアサーションです。たとえば、
public class MyClassSpecification
{
protected MyClass instance = new MyClass();
public class When_foobar_is_42 : MyClassSpecification
{
public When_foobar_is_42() {
this.instance.SetFoobar( 42 );
}
public class GetAnswer : When_foobar_is_42
{
private Int32 result;
public GetAnswer() {
this.result = this.GetAnswer();
}
public void should_return_42() {
Assert.AreEqual( 42, result );
}
}
}
}
テストランナーで次の出力が得られます。
MyClassSpecification+When_foobar_is_42+GetAnswer
should_return_42
質問で説明した2つの道と他のいくつかの道を辿っています...最初の選択肢は、ほとんどの人にとって非常に簡単で理解しやすいものです。私は個人的にBDDスタイル(2番目の例)が好きです。なぜなら、それは異なるコンテキストを分離し、それらのコンテキストの観察をグループ化するからです。唯一の本当の欠点は、より多くのコードを生成することです。そのため、きちんとしたテストが表示されるまで、コードを実行し始めると少し面倒に感じます。また、フィクスチャのセットアップを再利用するために継承を使用する場合、継承チェーンを出力するテストランナーが必要です。クラス" An_empty_stack"を考えますそれを再利用したいので、別のクラスを実行します:" When_five_is_pushed_on:An_empty_stack"あなたはそれを出力として、そして単に「When_five_is_pushed_on」ではありません。テストランナーがこれをサポートしていない場合、テストには次のような冗長情報が含まれます:" When_five_is_pushed_on_empty_stack:An_empty_stack"出力を良くするためだけに。
テストケースクラスの呼び出し:EmployeeReaderTestCaseと http:// xunitpatternsのようなmethods()の呼び出しに投票します。 com / Organization.html および http://xunitpatterns.com/Organization。 html#Test%20Naming%20Conventions