Is Assert.Fail() considered bad practice?

前端 未结 14 1141
面向向阳花
面向向阳花 2021-01-31 07:20

I use Assert.Fail a lot when doing TDD. I\'m usually working on one test at a time but when I get ideas for things I want to implement later I quickly write an empty test where

相关标签:
14条回答
  • 2021-01-31 07:38

    Beware Assert.Fail and its corrupting influence to make developers write silly or broken tests. For example:

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

    This is silly, because the try-catch is redundant. A test fails if it throws an exception.

    Also

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

    This is broken, the test will always pass whatever the outcome of the Divide function. Again, a test fails if and only if it throws an exception.

    0 讨论(0)
  • 2021-01-31 07:41

    With the good code I usually do:

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

    With the test code I usually do:

    @Test
    void testSomething() {
         // TODO void test Something
         Assert.assert("Some descriptive text about what to test")
    }
    

    If using JUnit, and don't want to get the failure, but the error, then I usually do:

    @Test
    void testSomething() {
         // TODO void test Something
         throw new NotSupportedOperationException("Some descriptive text about what to test")
    }
    
    0 讨论(0)
  • 2021-01-31 07:45

    MS Test has Assert.Fail() but it also has Assert.Inconclusive(). I think that the most appropriate use for Assert.Fail() is if you have some in-line logic that would be awkward to put in an assertion, although I can't even think of any good examples. For the most part, if the test framework supports something other than Assert.Fail() then use that.

    0 讨论(0)
  • 2021-01-31 07:45

    I think you should ask yourselves what (upfront) testing should do.

    First, you write a (set of) test without implmentation. Maybe, also the rainy day scenarios.

    All those tests must fail, to be correct tests: So you want to achieve two things: 1) Verify that your implementation is correct; 2) Verify that your unit tests are correct.

    Now, if you do upfront TDD, you want to execute all your tests, also, the NYI parts. The result of your total test run passes if: 1) All implemented stuff succeeds 2) All NYI stuff fails

    After all, it would be a unit test ommision if your unit tests succeeds whilst there is no implementation, isnt it?

    You want to end up with something of a mail of your continous integration test that checks all implemented and not implemented code, and is sent if any implemented code fails, or any not implemented code succeeds. Both are undesired results.

    Just write an [ignore] tests wont do the job. Neither, an asserts that stops an the first assert failure, not running other tests lines in the test.

    Now, how to acheive this then? I think it requires some more advanced organisation of your testing. And it requires some other mechanism then asserts to achieve these goals.

    I think you have to split up your tests and create some tests that completly run but must fail, and vice versa.

    Ideas are to split your tests over multiple assemblies, use grouping of tests (ordered tests in mstest may do the job).

    Still, a CI build that mails if not all tests in the NYI department fail is not easy and straight-forward.

    0 讨论(0)
  • 2021-01-31 07:48

    For this scenario, rather than calling Assert.Fail, I do the following (in C# / NUnit)

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

    It is more explicit than an Assert.Fail.

    There seems to be general agreement that it is preferable to use more explicit assertions than Assert.Fail(). Most frameworks have to include it though because they don't offer a better alternative. For example, NUnit (and others) provide an ExpectedExceptionAttribute to test that some code throws a particular class of exception. However in order to test that a property on the exception is set to a particular value, one cannot use it. Instead you have to resort to 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); 
        }
    }
    

    The xUnit.Net method Assert.Throws makes this a lot neater without requiring an Assert.Fail method. By not including an Assert.Fail() method xUnit.Net encourages developers to find and use more explicit alternatives, and to support the creation of new assertions where necessary.

    0 讨论(0)
  • 2021-01-31 07:49

    It was deliberately left out. This is Brad Wilson's reply as to why is there no Assert.Fail():

    We didn't overlook this, actually. I find Assert.Fail is a crutch which implies that there is probably an assertion missing. Sometimes it's just the way the test is structured, and sometimes it's because Assert could use another assertion.

    0 讨论(0)
提交回复
热议问题