TDDを行う際にAssert.Failを頻繁に使用します。私は通常一度に1つのテストに取り組んでいますが、後で実装したいもののアイデアを得ると、テストメソッドの名前がtodoリストのようなものとして実装したいものを示す空のテストをすばやく書きます。忘れないように、本文にAssert.Fail()を入れます。
XUnit.Netを試してみると、Assert.Failが実装されていないことがわかりました。もちろん、いつでもAssert.IsTrue(false)を使用できますが、これは私の意図を伝えません。 Assert.Failは意図的に実装されていないという印象を受けました。これは悪い習慣と見なされますか?もしそうなら、なぜですか?
@マーティン・メレディスそれは私がやっていることとはまったく異なります。最初にテストを作成してから、それを機能させるコードを実装します。通常、一度にいくつかのテストを考えます。または、他の作業をしているときに書くテストについて考えます。そのとき、空の失敗したテストを書いて覚えておきます。テストを作成する頃には、テストファーストできちんと動作します。
@Jimmehそれは良いアイデアのようです。無視されたテストは失敗しませんが、別のリストに表示されます。それを試してみてください。
@Matt Howells素晴らしいアイデア。この場合、NotImplementedExceptionはassert.Fail()よりも意図を伝えます
@Mitch Wheatそれが私が探していたものです。悪用される別の方法で悪用されるのを防ぐために除外されたようです。
このシナリオでは、Assert.Failを呼び出すのではなく、次のことを行います(C#/ NUnitで)
[Test]
public void MyClassDoesSomething()
{
throw new NotImplementedException();
}
Assert.Failよりも明示的です。
Assert.Fail()よりも明示的なアサーションを使用することが望ましいという一般的な合意があるようです。しかし、ほとんどのフレームワークは、より良い代替手段を提供しないため、それを含める必要があります。たとえば、NUnit(およびその他)はExpectedExceptionAttributeを提供して、特定のコードが例外の特定のクラスをスローすることをテストします。ただし、例外のプロパティが特定の値に設定されていることをテストするために、それを使用することはできません。代わりに、Assert.Failに頼らなければなりません:
[Test]
public void ThrowsExceptionCorrectly()
{
const string BAD_INPUT = "bad input";
try
{
new MyClass().DoSomething(BAD_INPUT);
Assert.Fail("No exception was thrown");
}
catch (MyCustomException ex)
{
Assert.AreEqual(BAD_INPUT, ex.InputString);
}
}
XUnit.NetのAssert.Throwsメソッドは、Assert.Failメソッドを必要とせずに、これをよりきれいにします。 Assert.Fail()メソッドを含めないことにより、xUnit.Netは、開発者がより明示的な代替を見つけて使用し、必要に応じて新しいアサーションの作成をサポートすることを奨励します。
意図的に除外されました。これは、Assert.Fail()がない理由に関するBrad Wilsonの回答です。
実際、これは見逃していません。 Assert.Failは松葉杖であり、おそらくアサーションが欠落していることを意味します。場合によっては、テストの構造がそのままであり、Assertは別のアサーションを使用できるためです。
単純な値の比較以外のロジックでテストが失敗することを検出した場合の処理には、常にAssert.Fail()を使用してきました。例として:
try
{
// Some code that should throw ExceptionX
Assert.Fail("ExceptionX should be thrown")
}
catch ( ExceptionX ex )
{
// test passed
}
したがって、フレームワークにAssert.Fail()がないことは間違いのように見えます。 Assertクラスにパッチを適用してFail()メソッドを含め、フレームワーク開発者にパッチを提出し、それを追加する理由をお勧めします。
ワークスペースで意図的に失敗するテストを作成する練習については、コミットする前にテストを実装するように自分に思い出させるために、それは私にとって素晴らしい練習のようです。
ユニットテストにはMbUnitを使用します。テストを無視するオプションがあり、テストスイートにオレンジ(緑または赤ではなく)として表示されます。おそらくxUnitには似たようなものがあり、メソッドにアサートする必要さえありません。これは、迷惑なほど異なる色で表示されるため見逃しにくいからです。
編集:
MbUnitでは、次のようになります。
[Test]
[Ignore]
public void YourTest()
{ }
これは、設計で例外をスローするコードのテストを作成するときに使用するパターンです。
[TestMethod]
public void TestForException()
{
Exception _Exception = null;
try
{
//Code that I expect to throw the exception.
MyClass _MyClass = null;
_MyClass.SomeMethod();
//Code that I expect to throw the exception.
}
catch(Exception _ThrownException)
{
_Exception = _ThrownException
}
finally
{
Assert.IsNotNull(_Exception);
//Replace NullReferenceException with expected exception.
Assert.IsInstanceOfType(_Exception, typeof(NullReferenceException));
}
}
私見、これはAssert.Fail()を使用するよりも例外をテストするより良い方法です。この理由は、例外がスローされたことをテストするだけでなく、例外の種類もテストするためです。これは、Matt Howellsの回答に似ていますが、finallyブロックを使用したIMHOはより堅牢です。
明らかに、例外の入力文字列などをテストするために他のAssertメソッドを含めることは可能です。私のパターンに対するコメントと意見に感謝します。
個人的には、最終的にテストの記述に慣れる限り、テストスイートをこのようなToDoリストとして使用しても問題ありませんbefore合格するコードを実装します。
そうは言っても、私はこのアプローチを自分で使用していましたが、そうすることで、あまりにも多くのテストを前もって書くという道にたどり着くことがわかりました。あなたは私見について少し早すぎる設計に関する決定を下すことになります。
ちなみにMSTestでは、標準のテストテンプレートはサンプルの最後にAssert.Inconclusiveを使用します。
私の知る限り、xUnit.NETフレームワークは非常に軽量であることが意図されており、開発者が明示的な障害状態を使用することを奨励するために、意図的にFailをカットしました。
良いコードで私は通常やる:
void goodCode() {
// TODO void goodCode()
throw new NotSupportedOperationException("void goodCode()");
}
私が通常行うテストコードでは:
@Test
void testSomething() {
// TODO void test Something
Assert.assert("Some descriptive text about what to test")
}
JUnitを使用していて、エラーではなくエラーを取得したい場合、通常は次のようにします。
@Test
void testSomething() {
// TODO void test Something
throw new NotSupportedOperationException("Some descriptive text about what to test")
}
ワイルドな推測:Assert.Failを差し控えるのは、テストコードを記述する良い方法は、悪い場合にはAssert.Failにつながる巨大なスパゲッティのヒープであると考えるのをやめることです。 [追加して編集:他の人の答えはこれを広く確認しますが、引用符で]
それはあなたがしていることではないので、xUnit.Netが過保護になっている可能性があります。
それとも、彼らはそれが非常にまれであり、不必要であるほど非直交的であると考えるだけかもしれません。
ThisCodeHasNotBeenWrittenYetと呼ばれる関数を実装することを好みます(入力を簡単にするため、実際はもっと短いものです)。それよりも明確に意図を伝えることができず、正確な検索語があります。
それが失敗するか、実装されていない(リンカーエラーを引き起こす)か、コンパイルされないマクロであるかは、現在の好みに合わせて変更できます。たとえば、isが終了したものを実行したい場合は、失敗します。それらすべてを取り除くために座っているとき、あなたはコンパイルエラーが欲しいかもしれません。
Assert.Fail
およびその破壊的な影響により、開発者はばかげたテストまたは壊れたテストを記述できます。例えば:
[TestMethod]
public void TestWork()
{
try {
Work();
}
catch {
Assert.Fail();
}
}
Try-catchは冗長であるため、これはばかげています。例外をスローすると、テストは失敗します。
また
[TestMethod]
public void TestDivide()
{
try {
Divide(5,0);
Assert.Fail();
} catch { }
}
これは壊れており、テストは常にDivide関数の結果にかかわらず合格します。繰り返しますが、テストは例外をスローした場合にのみ失敗します。
私はあなたが(前もって)テストが何をすべきか自分自身に尋ねるべきだと思う。
最初に、実装なしでテスト(のセット)を作成します。たぶん、雨の日のシナリオも。
これらのテストはすべて、正しいテストであるために失敗する必要があります。したがって、次の2つのことを達成する必要があります。1)実装が正しいことを確認します。 2)ユニットテストが正しいことを確認します。
さて、前もってTDDを行う場合、すべてのテスト、およびNYIの部分を実行する必要があります。合計テスト実行の結果は、次の場合に合格します:1)すべての実装されたものが成功する2)すべてのNYIのものが失敗する
結局のところ、実装が存在しない状態でユニットテストが成功した場合、ユニットテストの省略になります。
実装されたコードと実装されていないコードをすべてチェックし、実装されたコードが失敗するか、実装されていないコードが成功した場合に送信される、継続的な統合テストのメールになりたいと考えています。どちらも望ましくない結果です。
[無視]テストを書くだけで仕事はできません。また、最初のアサート失敗を停止するアサートは、テスト内の他のテスト行を実行しません。
さて、これをどうやって達成するのですか?テストをさらに高度に編成する必要があると思います。そして、これらの目標を達成するために他のメカニズムが必要です。
テストを分割し、完全に実行されるが失敗しなければならないテストを作成する必要があると思います。
アイデアは、テストを複数のアセンブリに分割し、テストのグループ化を使用することです(mstestで順序付けられたテストが仕事をするかもしれません)。
それでも、NYI部門のすべてのテストが失敗したわけではない場合にメールを送信するCIビルドは、簡単で簡単ではありません。
なぜAssert.Fail
例外がスローされるべきだと言って?それは不要です。なぜExpectedException
属性を使用しないのですか?
単に失敗するテストを作成し、そのコードを作成してからテストを作成する場合。これはテスト駆動開発ではありません。
技術的には、テスト駆動開発を正しく使用している場合、Assert.fail()は必要ありません。
Todoリストの使用、または作業にGTD方法論の適用を考えたことがありますか?
MSテストにはAssert.Fail()がありますが、Assert.Inconclusive()もあります。 Assert.Fail()の最も適切な使用法は、アサーションを配置するのが面倒なインラインロジックがある場合ですが、良い例は考えられません。ほとんどの場合、テストフレームワークがAssert.Fail()以外の何かをサポートしている場合、それを使用します。