Assert.Fail()被认为是不好的做法?

在进行TDD时,我使用Assert.Fail很多。 我通常每次都在做一个testing,但是当我想了解我想要实现的东西时,我很快写了一个空testing,其中testing方法的名称表明了我想要实现的一个todo-list。 为了确保我不会忘记我在正文中放置了一个Assert.Fail()。

当试用xUnit.Net时,我发现他们没有实现Assert.Fail。 当然你总是可以Assert.IsTrue(false),但是这并不能传达我的意图。 我得到了印象Assert.Fail不是故意实现的。 这被认为是不好的做法? 如果是这样的话


@马丁梅雷迪思这不完全是我做的。 我首先写一个testing,然后实现代码来使其工作。 通常我会同时考虑多个testing。 或者当我正在做其他事情时,我会考虑写一个testing。 那就是当我写一个空的失败testing来记住。 当我开始写testing的时候,我整齐地testing了一下。

@Jimmeh这看起来像个好主意。 忽略的testing不会失败,但仍然显示在一个单独的列表中。 必须尝试一下。

@Matt Howells伟大的想法。 NotImplementedException比assert.Fail()更好地传递意图

@米奇麦这是我正在寻找。 它似乎被排除在外,以防止滥用另一种方式虐待它。

对于这种情况,而不是调用Assert.Fail,我做了以下(在C#/ NUnit中)

[Test] public void MyClassDoesSomething() { throw new NotImplementedException(); } 

它比Assert.Fail更明确。

似乎普遍认为最好使用比Assert.Fail()更明确的断言。 大多数框架必须包含它,因为它们没有提供更好的select。 例如,NUnit(和其他)提供ExpectedExceptionAttribute来testing某些代码抛出一个特定的exception类。 但是,为了testingexception的属性被设置为一个特定的值,一个不能使用它。 相反,你必须诉诸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鼓励开发人员查找并使用更多显式的替代方法,并在必要时支持创build新的断言。

它被故意排除在外。 这是Brad Wilson的答复,为什么没有Assert.Fail():

其实,我们并没有忽视这一点。 我发现Assert.Fail是一个拐杖,意味着可能缺less一个断言。 有时候这只是testing的结构,有时候是因为Assert可以使用另一个断言。

我一直使用Assert.Fail()来处理那些你已经发现testing应该通过逻辑失败而不是简单的值比较的情况。 举个例子:

 try { // Some code that should throw ExceptionX Assert.Fail("ExceptionX should be thrown") } catch ( ExceptionX ex ) { // test passed } 

因此,在框架中缺lessAssert.Fail()对我来说看起来是个错误。 我build议修补Assert类以包含一个Fail()方法,然后将修补程序提交给框架开发人员,以及添加它的推理。

至于你的做法是在你的工作空间中创build有意失败的testing,提醒自己在提交之前执行它们,这对我来说是一个很好的练习。

我使用MbUnit进行unit testing。 他们可以select忽略testing,在testing套件中显示为橙色(而不是绿色或红色)。 也许xUnit有类似的东西,这意味着你甚至不需要在方法中join任何东西,因为它会以令人讨厌的颜色显示出来,所以很难错过?

编辑:

在MbUnit中有以下几种方式:

 [Test] [Ignore] public void YourTest() { } 

就我个人而言,使用testing套件作为这样的待办事项列表没有任何问题,只要您实现代码通过之前最终完成写testing。

话虽如此,我自己也曾经使用过这种方法,但是现在我发现这样做会导致我在前期编写太多的testing,这种方式很奇怪,就像是不写testing的逆向问题:你最终做出有关devise的决定有点过早恕我直言。

顺便提一句,在MSTest中,标准的testing模板在其样本的末尾使用了Assert.Inclusive。

AFAIK xUnit.NET框架的目的是非常轻量级,是的,他们故意故意切断故障,鼓励开发人员使用明确的故障条件。

疯狂的猜测:扣住Assert.Fail的目的是阻止你认为编写testing代码的好方法就像是一大堆通向Assert.Fail的意大利面。 [编辑补充:其他人的回答广泛证实这一点,但用引用]

由于这不是你正在做的事情,有可能xUnit.Net是过度保护。

或者,也许他们只是认为这是非常罕见的,如此不正确,以至于不必要。

我更喜欢实现一个叫做ThisCodeHasNotBeenWrittenYet的函数(实际上是简单的,为了便于打字)。 不能更清楚地传达意图,而且你有一个精确的search术语。

无论是失败还是未实现(引发链接器错误),还是不能编译的macros,都可以根据当前的偏好进行更改。 例如,当你想运行完成的东西,你想要失败。 当你坐下来摆脱他们,你可能会想要一个编译错误。

有了这个好的代码我通常会这样做:

 void goodCode() { // TODO void goodCode() throw new NotSupportedOperationException("void goodCode()"); } 

我通常使用testing代码:

 @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") } 

这是我在写代码testing时使用的模式,我想通过devise抛出一个exception:

 [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()testingexception的更好方法。 这样做的原因是,我不仅testing抛出的exception,而且还testingexceptiontypes。 我意识到,这是从马特Howells的答案类似,但恕我直言,使用finally块更强大。

显然,还可以包含其他的Assert方法来testingexceptioninputstring等。我将不胜感激您对我的模式的意见和看法。

谨防Assert.Fail及其破坏影响,使开发人员编写愚蠢或破坏的testing。 例如:

 [TestMethod] public void TestWork() { try { Work(); } catch { Assert.Fail(); } } 

这很愚蠢,因为try-catch是多余的。 如果引发exception,则testing失败。

 [TestMethod] public void TestDivide() { try { Divide(5,0); Assert.Fail(); } catch { } } 

这被打破了,testing总是会传递任何分界function的结果。 同样,一个testing失败,当且仅当它抛出一个exception。

如果你正在编写一个失败的testing,然后编写代码,然后编写testing。 这不是testing驱动开发。

从技术上讲,如果您正确使用testing驱动开发,则不需要Assert.fail()。

你有没有想过使用待办事项清单,或者将GTD方法应用于你的工作?

MStesting有Assert.Fail(),但也有Assert.Inconclusive() 。 我认为Assert.Fail()最合适的用法是,如果你有一些内联的逻辑,那么在插入一个断言的时候会很尴尬,尽pipe我甚至想不出任何好的例子。 大多数情况下,如果testing框架支持Assert.Fail()之外的其他东西,那就使用它。

为什么要用Assert.Fail来说应该抛出一个exception呢? 这是不必要的。 为什么不使用ExpectedException属性?

我想你应该问自己什么(前期)testing应该做的。

首先,你写一个(一套)testing没有implmentation。 也许,也是雨天的情景。

所有这些testing都必须失败,才能进行正确的testing:所以你需要做两件事情:1)validation你的实现是正确的; 2)确认你的unit testing是正确的。

现在,如果你预先做TDD,你想要执行所有的testing,也就是NYI的部分。 如果您的总testing运行的结果通过,如果:1)所有实现的东西成功2)所有NYI的东西失败

毕竟,如果你的unit testing成功,而没有执行,这将是一个unit testingommision,不是吗?

你想最终得到持续集成testing的邮件,检查所有已实现和未实现的代码,如果任何实现的代码失败,或者任何未实现的代码成功,则发送。 两者都是不希望的结果。

只要写一个[忽略]testing不会做这项工作。 也不要断言停止第一个断言失败,不在testing中运行其他testing线。

那么,如何实现这个呢? 我认为这需要一些更高级的testing组织。 而且这需要一些其他的机制,然后声称要实现这些目标。

我认为你必须分解你的testing,并创build一些testing完成运行,但必须失败,反之亦然。

想法是分裂您的testing在多个程序集,使用testing的分组(在mstest有序的testing可能做这个工作)。

尽pipe如此,如果不是所有NYI部门的testing都失败,那么CI构build邮件并不容易和直接。