unit-testing - 您如何对具有复杂输入输出的方法进行单元测试

标签 unit-testing tdd

当您有一个简单的方法时,例如 sum(int x, int y),编写单元测试很容易。您可以检查该方法是否正确地求和两个样本整数,例如 2 + 3 应该返回 5,然后您将检查某些“非凡”数字,例如负值和零。这些中的每一个都应该是单独的单元测试,因为单个单元测试应该包含单个断言。

当你有一个复杂的输入输出时你会怎么做?以 Xml 解析器为例。您可以有一个方法 parse(String xml) 接收字符串并返回一个 Dom 对象。您可以编写单独的测试来检查某些文本节点是否正确解析,属性是否解析正常,子节点属于父节点等。对于所有这些,我可以编写一个简单的输入,例如

<root><child/></root>

这将用于检查节点之间的父子关系等,以了解其余的期望。

现在,看看以下 Xml:
<root>
  <child1 attribute11="attribute 11 value" attribute12="attribute 12 value">Text 1</child1>
  <child2 attribute21="attribute 21 value" attribute22="attribute 22 value">Text 2</child2>
</root>

为了检查该方法是否正常工作,我需要检查许多复杂的条件,例如attribute11 和attribute12 属于element1,Text 1 属于child1 等。我不想在我的单元测试中放置多个断言。 我怎样才能做到这一点?

最佳答案

您所需要的只是在单独的测试中检查 SUT(被测系统)的一个方面。

[TestFixture]
    public class XmlParserTest
    {
        [Test, ExpectedException(typeof(XmlException))]
        public void FailIfXmlIsNotWellFormed()
        {
            Parse("<doc>");
        }

        [Test]
        public void ParseShortTag()
        {
            var doc = Parse("<doc/>");

            Assert.That(doc.DocumentElement.Name, Is.EqualTo("doc"));
        }

        [Test]
        public void ParseFullTag()
        {
            var doc = Parse("<doc></doc>");

            Assert.That(doc.DocumentElement.Name, Is.EqualTo("doc"));
        }

        [Test]
        public void ParseInnerText()
        {
            var doc = Parse("<doc>Text 1</doc>");

            Assert.That(doc.DocumentElement.InnerText, Is.EqualTo("Text 1"));
        }

        [Test]
        public void AttributesAreEmptyifThereAreNoAttributes()
        {
            var doc = Parse("<doc></doc>");

            Assert.That(doc.DocumentElement.Attributes, Has.Count(0));
        }

        [Test]
        public void ParseAttribute()
        {
            var doc = Parse("<doc attribute11='attribute 11 value'></doc>");

            Assert.That(doc.DocumentElement.Attributes[0].Name, Is.EqualTo("attribute11"));
            Assert.That(doc.DocumentElement.Attributes[0].Value, Is.EqualTo("attribute 11 value"));
        }

        [Test]
        public void ChildNodesInnerTextAtFirstLevel()
        {
            var doc = Parse(@"<root>
              <child1>Text 1</child1>
              <child2>Text 2</child2>
            </root>");

            Assert.That(doc.DocumentElement.ChildNodes, Has.Count(2));
            Assert.That(doc.DocumentElement.ChildNodes[0].InnerText, Is.EqualTo("Text 1"));
            Assert.That(doc.DocumentElement.ChildNodes[1].InnerText, Is.EqualTo("Text 2"));
        }

        // More tests 
        .....

        private XmlDocument Parse(string xml)
        {
            var doc = new XmlDocument();

            doc.LoadXml(xml);

            return doc;
        }
    }

这种方法有很多优点:
  • 容易定位缺陷 - 如果
    属性有问题
    解析,然后只测试
    属性会失败。
  • 小测试总是更容易理解

  • UPD:看看 Gerard Meszaros(xUnit 测试模式书的作者)说的话题:xunitpatterns

    One possibly contentious aspect of Verify One Condition per Test is what we mean by "one condition". Some test drivers insist on one assertion per test. This insistence may be based on using a Testcase Class per Fixture organization of the Test Methods and naming each test based on what the one assertion is verifying(E.g. AwaitingApprovalFlight.validApproverRequestShouldBeApproved.). Having one assertion per test makes such naming very easy but it does lead to many more test methods if we have to assert on many output fields. Of course, we can often comply with this interpretation by extracting a Custom Assertion (page X) or Verification Method (see Custom Assertion) that allows us to reduce the multiple assertion method calls into one. Sometimes that makes the test more readable but when it doesn't, I wouldn't be too dogmatic about insisting on a single assertion.

    关于unit-testing - 您如何对具有复杂输入输出的方法进行单元测试,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3034730/

    相关文章:

    java - 单元测试时的 RxJava Schedulers.immediate() 行为

    c# - Moq 具有匿名类型的函数

    unit-testing - 涉及随机数的单元测试算法

    unit-testing - 如何在单元测试中使用外部数据?

    unit-testing - 基于部分单元测试的软件方法

    drupal - Drupal 7 上的 PHPunit

    java - 单元测试数据库连接和有关数据库相关代码和单元测试的一般问题

    unit-testing - 通过gradle中的控制台运行组testng测试

    c# - 如何仅对列表中的一部分项目分配属性?

    ruby-on-rails - 如何在 Capybara finder 中使用正则表达式?