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

时间:2010-06-14 02:35:32

标签: unit-testing tdd

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

当您有复杂的输入输出时,您会怎么做?以一个Xml解析器为例。您可以使用单个方法解析(String xml)来接收String并返回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等。我不想放置多个断言在我的单元测试中。我该如何实现?

7 个答案:

答案 0 :(得分:4)

您需要的只是在单独的测试中检查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;
        }
    }

这种方法有很多好处:

  1. 容易缺陷的位置 - 如果 属性有问题 解析,然后只测试 属性将失败。
  2. 小测试总是更容易理解
  3. UPD:看看Gerard Meszaros(xUnit测试模式的作者书)关于主题的内容:xunitpatterns

      

    一个可能有争议的方面   验证每个测试的一个条件是什么   我们的意思是“一个条件”。一些测试   司机坚持每一个断言   测试。这种坚持可以基于   使用每个Fixture的Testcase类   组织测试方法和   根据一个测试命名每个测试   断言正在验证(例如   AwaitingApprovalFlight.validApproverRequestShouldBeApproved)。   每次测试都有一个断言   这样的命名很容易,但确实很有用   如果我们有更多的测试方法   在许多输出字段上断言。的   当然,我们经常可以遵守这一点   通过提取自定义来解释   断言(第X页)或验证   方法(参见自定义断言)即   允许我们减少倍数   断言方法调用一个。   有时这会使测试更多   可读但如果没有,我   不会太教条   坚持一个断言。

答案 1 :(得分:1)

多项测试。

答案 2 :(得分:1)

使用多个测试。同样的限制适用。您应该测试一些正常的操作案例,一些失败案例和一些边缘案例。

同样地,你可以假设如果sum(x,y)适用于x的某些值,它将与其他值一起使用,你可以假设如果XML解析器可以解析2个节点的序列,它可以还解析了100个节点的序列。

答案 3 :(得分:1)

详细说明Ian的简洁回答:将XML的设置作为设置,并进行单独的单独测试,每个测试都有自己的断言。这样你就不会重复设置逻辑,但你仍然可以很好地了解解析器的错误。

答案 4 :(得分:0)

使用Nunit Fluent语法

Assert.That( someString,
      Is.Not.Null
      .And.Not.Empty
      .And.EqualTo("foo")
      .And.Not.EqualTo("bar")
      .And.StartsWith("f"));

答案 5 :(得分:0)

我有类似的要求,我希望各种输入集有1个Assert。请关闭下面的链接,我在博客上写道。

Writing better unit tests

这也适用于你的概率。构造一个工厂类,其中包含构造“复杂”输入集的逻辑。单元测试用例只有一个Assert。

希望这有帮助。

谢谢, 维杰。

答案 6 :(得分:0)

您可能还想使用自己的断言(这取自您自己的问题):

attribute11和attribute12属于element1

('attribute11 ', 'attribute12').belongsTo('element1');

('element1 attribute11').length

BTW,这与jQuery类似。您将此字符串存储在复杂的图形存储库中。您如何对一个非常复杂的图形连接数据库进行单元测试?