質問

時々、何もアサートしない単体テストに遭遇します。今朝私が遭遇した特定の例は、条件が満たされたときにログ ファイルが書き込まれることをテストすることでした。エラーがスローされなければテストは成功したと想定されていました。

私個人としてはこれに問題はありませんが、アサーションが関連付けられていない単体テストを記述するのは少し「コードの臭い」があるように思えます。

これについて人々はどう思っているのか気になりますか?

役に立ちましたか?

解決

これは公式の方法です:

// Act
Exception ex = Record.Exception(() => someCode());

// Assert
Assert.Null(ex);

他のヒント

これは単に最小限のテストであり、そのように文書化する必要があります。実行時に爆発しないことのみを検証します。このようなテストの最悪の部分は、それらがセキュリティの誤った感覚を提示することです。コードカバレッジは上がりますが、それは幻想です。非常に悪臭。

アサーションがない場合、テストではありません。

やや怠け者-そこにアサーションを取得する方法を理解するのに少し時間がかかるかもしれませんが、それがあなたが期待したことをしたことを知ることは価値があります。

これらは煙テストとして知られ、一般的です。基本的な健全性チェックです。しかし、あなたが持っているテストの種類はそれらだけではないはずです。別のテストで何らかの検証を行う必要があります。

このようなテストは臭いがします。ファイルが書き込まれたこと、少なくとも変更時刻が更新された可能性があることを確認する必要があります。

このように書かれたテストをかなり見たことがありますが、結局何もテストしませんでした。つまり、コードは機能しませんでしたが、爆発もしませんでした。

テスト対象のコードが例外をスローしないという明示的な要件があり、この事実を明示的に呼び出す(要件ドキュメントとしてテストする)場合は、次のようにします。

try
{
  unitUnderTest.DoWork()
}
catch
{
  Assert.Fail("code should never throw exceptions but failed with ...")
}

...しかし、これはまだ否定的なことを証明しようとしているため、私にはまだ少し臭いがあります。

ある意味では、コードは例外をスローしないという暗黙のアサーションを作成しています。もちろん、実際にファイルを取得して適切な行を見つける方がより価値がありますが、何もないよりはましだと思います。

一般に、統合テストでこれが発生していることがわかります。完了に成功したものがあれば十分です。この場合、私はそれでクールです。

単体テストで何度も見た場合、テストが実際にどれほど有用かについて興味があります。

編集:OPで指定された例では、テスト可能な結果(ログファイルの結果)があります。

これは、特に代替策がまったくテストされていない場合に、実用的な解決策となります。

問題は、呼び出されたすべての関数がノーオペレーションだった場合、テストに合格することです。しかし、副作用が期待したものであることを検証することが現実的でない場合もあります。理想的な世界では、すべてのテストのチェックを書くのに十分な時間があるでしょう...しかし、私はそこに住んでいません。

私がこのパターンを使用したもう1つの場所は、いくつかのパフォーマンステストをユニットテストに埋め込むことです。これは、すべてのビルドを実行する簡単な方法だからです。テストは何もアサートしませんが、テストにかかった時間を測定して記録します。

私は以前にこのようなものを見たことがありますが、これはコードカバレッジの数値を支えるためだけに行われたと思います。おそらく実際にコードの動作をテストしているわけではありません。いずれにせよ、明確にするために、テストで意図(意図)を文書化することに同意します。

テストの名前はこれを文書化する必要があります。

void TestLogDoesNotThrowException(void) {
    log("blah blah");
}

アサーションなしでログが書き込まれたかどうかをテストはどのように検証しますか?

正しくログを記録していることを確認した単体テストを書いたことがないことを認めなければなりません。しかし、私はそれについて考え、このディスカッション JUnitとLog4Jでどのようにできるのか。あまりきれいではありませんが、うまくいくようです。

テストでは常に何かをアサートする必要があります。

これは常に行っています。 JMockを使用して依存関係をモックするため、ある意味ではJMockフレームワークがアサーションを実行していると思いますが、これは次のようになります。テストしたいコントローラーがあります:

Class Controller {
  private Validator validator;

  public void control(){
    validator.validate;
  }

  public setValidator(Validator validator){ this.validator = validator; }
}

今、Controllerをテストするとき、Validatorには独自のテストがあるため、Validatorをテストする必要はありません。したがって、validateを呼び出すことを確認するために、JMockでテストを行います。

public void testControlShouldCallValidate(){
  mockValidator.expects(once()).method("validate");
  controller.control;
}

これですべてです。「アサーション」はありません。確認するには、コントロールと「検証」を呼び出すとメソッドが呼び出されなかった場合、JMockフレームワークは例外(" expected method not called"など)をスローします。

これらは至る所にあります。基本的にアサーションをセットアップしてから、テストされたメソッドを呼び出すため、少し逆になります。

私は時々、選択した単体テスト フレームワーク (NUnit) を使用して、コードの特定の部分へのエントリ ポイントとして機能するメソッドを構築します。これらのメソッドは、コードのサブセットのパフォーマンス、メモリ消費量、およびリソース消費量をプロファイリングするのに役立ちます。

これらのメソッドは明らかに単体テストではありません (たとえマークが付いているとしても) [テスト] 属性) であり、常に無視されるようにフラグが立てられ、ソース管理にチェックインされるときに明示的に文書化されます。

また、これらのメソッドを Visual Studio デバッガーのエントリ ポイントとして使用することもあります。Resharper を使用してテストに直接ステップインし、次にデバッグするコードにステップインします。これらのメソッドは、ソース管理まで到達しないか、独自のアサートを取得します。

私の「実際の」単体テストは通常​​の TDD サイクル中に構築され、常に直接ではありませんが、常に何かをアサートします。アサーションがモック フレームワークの一部である場合もあれば、同様のアサーションを 1 つのメソッドにリファクタリングできる場合もあります。これらのリファクタリングされたメソッドの名前は、わかりやすいように常に接頭辞「Assert」で始まります。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top