代码之家  ›  专栏  ›  技术社区  ›  Mendelt

Assert.Fail()是否被认为是错误的做法?

  •  66
  • Mendelt  · 技术社区  · 17 年前

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


    @马丁梅雷迪斯 我不是这么做的。我确实先写一个测试,然后实现代码使它工作。通常我一次想到几个测试。或者当我在做其他事情时,我想写一个测试。那就是我写一个空的失败测试来记忆的时候。当我开始写测试的时候,我首先干净利落地完成了测试。

    @吉米 这看起来是个好主意。被忽略的测试不会失败,但它们仍然显示在单独的列表中。我必须试一下。

    @马特豪厄尔斯 好主意。在这种情况下,NotImplementedException比assert.Fail()更好地传达意图

    @米奇小麦 这就是我要找的。它似乎被排除在外,以防止它被滥用的另一种方式,我滥用它。

    13 回复  |  直到 17 年前
        1
  •  54
  •   Matt Howells    17 年前

    对于这个场景,我不调用Assert.Fail,而是执行以下操作(在C#/NUnit中)

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

    它比Assert.Fail更显式。

    人们似乎普遍认为,最好使用比Assert.Fail()更明确的断言。不过,大多数框架都必须包含它,因为它们没有提供更好的替代方案。例如,NUnit(和其他)提供了一个ExpectedExceptionAttribute来测试某些代码是否抛出特定的异常类。但是,为了测试异常的属性是否设置为特定值,不能使用它。相反,您必须求助于断言。失败:

    [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); 
        }
    }
    

        2
  •  17
  •   Mitch Wheat    13 年前

    这是故意漏掉的。这是Brad Wilson关于为什么没有Assert.Fail()的回答:

    查找断言。失败是 缺少断言。有时候只是 测试的结构方式,以及 有时是因为断言可以 使用另一个断言。

        3
  •  11
  •   Craig Trader    17 年前

    我一直使用Assert.Fail()来处理您检测到测试应该通过简单值比较之外的逻辑失败的情况。例如:

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

        4
  •  5
  •   Jimmeh    17 年前

    我使用MbUnit进行单元测试。他们可以选择忽略测试,这些测试在测试套件中显示为橙色(而不是绿色或红色)。也许xUnit也有类似的功能,这意味着您甚至不必在方法中添加任何断言,因为它会以令人恼火的不同颜色显示,因此很难错过?

    编辑:

    在MbUnit中,其方式如下:

    [Test]
    [Ignore]
    public void YourTest()
    { } 
    
        5
  •  4
  •   lexx    17 年前

    [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));
        }
    }
    

    IMHO这是一种比使用Assert.Fail()更好的异常测试方法。这样做的原因是,我不仅要测试抛出的异常,还要测试异常类型。我意识到这与Matt Howells的答案相似,但IMHO使用finally块更可靠。

    显然,仍然可以包含其他断言方法来测试异常输入字符串等。如果您对我的模式有意见,我将不胜感激。

        6
  •  3
  •   Jim Burger    17 年前

    就我个人而言,我对使用测试套件作为这样的待办事项列表没有问题,只要您最终开始编写测试 之前 您实现了要传递的代码。

    话虽如此,我自己也曾使用过这种方法,尽管现在我发现这样做会导致我提前编写太多测试,这一点很奇怪,就像根本不编写测试的相反问题:你最终会过早地做出设计决策。

    顺便说一句,在MSTest中,标准测试模板在其示例末尾使用Assert.Inconclusive。

    另外,xUnit.NET框架的目的是非常轻量级的,是的,他们确实有意地减少了失败,以鼓励开发人员使用明确的失败条件。

        7
  •  2
  •   Steve Jessop    17 年前

    胡乱猜测:扣留Assert.Fail是为了阻止您认为编写测试代码的好方法是将一大堆意大利面条放入Assert.Fail中。[编辑添加:其他人的回答大致证实了这一点,但引用了一些话]

    因为这不是你正在做的,所以xUnit.Net可能是过度保护。

    或者他们只是认为这是如此罕见,如此非正统以至于没有必要。

    我更喜欢实现一个名为thiscodehasnewrittenyet的函数(实际上是更短的,以便于键入)。不能比这更清楚地传达意图,而且你有一个精确的搜索词。

    无论是失败的,还是未实现的(引发链接器错误),或者是未编译的宏,都可以根据您当前的偏好进行更改。例如,当您想要运行

        8
  •  2
  •   Daniel Fanjul    17 年前

    使用好的代码,我通常会:

    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")
    }
    
        9
  •  1
  •   Colonel Panic    11 年前

    当心 Assert.Fail

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

    而且

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

    如果这被打破,无论除法函数的结果如何,测试都将始终通过。同样,当且仅当测试抛出异常时,测试才会失败。

        10
  •  0
  •   Mez    17 年前

    如果您正在编写一个失败的测试,然后为它编写代码,然后编写测试。这不是测试驱动的开发。

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

    您是否想过使用待办事项列表,或将GTD方法应用于您的工作?

        11
  •  0
  •   Mark Cidade    17 年前

    MS测试已经完成 Assert.Fail() 但它也有 断言。非决定性的()

        12
  •  0
  •   Roland Roos    8 年前

    我认为你们应该问问自己(预先)测试应该做什么。

    首先,编写一个(一组)测试,而不进行实现。 也许,也是雨天的情景。

    因此,您希望实现两件事: 1) 验证您的实现是否正确; 2) 验证单元测试是否正确。

    在以下情况下,总测试运行的结果通过: 1) 所有实现的东西都成功了 2) 纽约所有的东西都失败了

    毕竟,如果您的单元测试在没有实现的情况下成功,这将是一个单元测试的目标,不是吗?

    只要写一个[忽略]测试就行了。

    那么,如何实现这一点呢? 我认为这需要更先进的测试组织。 它需要一些其他的机制来实现这些目标。

    想法是将测试拆分为多个程序集,使用测试分组(mstest中的有序测试可以完成这项工作)。

    尽管如此,如果不是纽约市政府部门的所有测试都失败,那么发送邮件的CI构建也不是简单直接的。

        13
  •  0
  •   double-beep hudson solomon    6 年前

    Assert.Fail 因为说应该抛出异常?这是没有必要的。为什么不直接使用 ExpectedException 属性

        14
  •  0
  •   Steve Hurcombe    6 年前

    这是我们的用例 .

    单元测试的一个重要目标是 不要碰数据库 .

    有时模拟没有正确发生,或者应用程序代码被修改,并且无意中进行了数据库调用。

    这在调用堆栈中可能相当深。异常可能会被捕获,这样它就不会冒泡,或者因为测试最初是使用数据库运行的,所以调用将起作用。

    Assert.Fail(“访问数据库”);

    Assert.Fail()全局运行,即使在不同的库中也是如此。因此,这是所有单元测试的总括。

    因此,我们失败得很快。