【问题标题】:Unit-testing of a constructor构造函数的单元测试
【发布时间】:2012-01-05 17:21:26
【问题描述】:

我正在实验室进行单元测试,下面是我正在测试的应用程序的一段代码。大多数单元测试已经完成,但是关于下面的构造函数,我只是不知道如何测试它。例如,构造函数究竟对数组元素做了什么?什么是测试构造函数的好方法?

是否有善良的灵魂可以让我朝正确的方向前进?

  public struct Point { 
    public int x, y;

    public Point(int a, int b) {
      x = a;
      y = b;
    }
  }

...

  public Triangle(Point[] s) {
    sides = new double[s.Length];
    sides[0] = Math.Sqrt(Math.Pow((double)(s[1].x - s[0].x), 2.0) + Math.Pow((double)(s[1].y - s[0].y), 2.0));
    sides[1] = Math.Sqrt(Math.Pow((double)(s[1].x - s[2].x), 2.0) + Math.Pow((double)(s[1].x - s[2].x), 2.0));
    sides[2] = Math.Sqrt(Math.Pow((double)(s[2].x - s[0].x), 2.0) + Math.Pow((double)(s[2].x - s[0].x), 2.0));
  }

...

        [TestMethod()]
        public void TriangleConstructorTest1()
        {
            Point[] s = null; // TODO: Initialize to an appropriate value
            Triangle target = new Triangle(s);
            Assert.Inconclusive("TODO: Implement code to verify target");
        }

【问题讨论】:

  • 你确定他们要求你也测试构造函数吗?对我来说似乎毫无意义,因为你只是在做一些任务。
  • sides 是否以任何方式暴露? Triangle可以使用的公共属性是什么?
  • @Tudor:实际上我倾向于不同意。因为它正在做分配,所以它可能应该进行单元测试以确保它分配了预期的内容。但这只是我的 0.02 美元,每个人对待单元测试的方式都不同。
  • +1 给您的老师和/或教育机构,用于教学单元测试。 :)
  • 另外,拥有公共属性比拥有公共字段更好。 IE。 public Point[] Sides { get; set; } 而不是 public Point[] sides;

标签: c# unit-testing mstest


【解决方案1】:

也许我遗漏了一些东西,但这样做不行吗?

   [TestMethod()]
        public void PointConstructorTest1()
        {
            Point target = new Point(1.5, 2.0);
            Assert.AreEqual(1.5, target.x);
            Assert.AreEqual(2.0, target.y);
        }

测试变量分配并没有多大意义……

【讨论】:

  • 其实我发现测试任务很有价值。如果内部表示发生更改等,很高兴知道更改没有破坏现有测试。因此,我倾向于为我的所有构造函数甚至简单属性编写单元测试,但这只是我的 0.02 美元
  • 这是一个很好的点单元测试,我想他是在问如何对 Triangle 构造函数进行单元测试。
【解决方案2】:

你说的是Traingle-constructor,不是吗?

看起来它正在使用Pythagorean theorem 来计算三角形边的长度。
所以你应该测试这个计算是否正确。

此外,您可以检查构造函数是否检测到无效参数,例如:

[TestMethod]
[ExpectedException(typeof(ArgumentNullException))]
public void Cannot_Create_Passing_Null()
{
   new Triangle(null);
}
[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void Cannot_With_Less_Than_Three_Points()
{
   new Triangle(new[] { new Point(0, 0), new Point(1, 1) });
}
[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void Cannot_Create_With_More_Than_Three_Points()
{
   new Triangle(new[] { new Point(0, 0), new Point(1, 1), new Point(2, 2), new Point(3, 3) });
}
[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void Cannot_Create_With_Two_Identical_Points()
{
   new Triangle(new[] { new Point(0, 0), new Point(0, 0), new Point(1, 1) });
}
[TestMethod]
[ExpectedException(typeof(ArgumentException))]
public void Cannot_Create_With_Empty_Array()
{
   new Triangle(new Point[] { });
}

【讨论】:

    【解决方案3】:

    由于最初问题中的一些不一致之处很难回答,但我将根据您的构造函数代码而不是您的示例测试来回答。

    首先,我会测试一个点 3 的数组是否会引发适当的异常(您应该检查并在构造函数中抛出该异常)。

    首先,如果点数组不好,我会让你的构造函数抛出:

        public Triangle(Point[] s)
        {
            // you could use more specific ArgumentNullException for first,
            // IllegalOperationException for second, etc, you get the point 
            // (no pun intended).
            if (s== null || s.Length != 3 || s.Any(x => x == null)) 
                throw new ArgumentException("s");
            ...
        }
    

    然后,我会测试 null 或不正确的长度

        [TestMethod]
        [ExpectedException(typeof(ArgumentException))]
        public void TriangleConstructorWithNullPoints()
        {
            Point[] s = null; 
            Triangle target = new Triangle(s);
        }
    
    [TestMethod]        
    [ExpectedException(typeof(ArgumentException))]        
    public void TriangleConstructorWithFourPoints()        
    {
        Point[] s = new Point[4];
        Triangle target = new Triangle(s);        
    }
    

    然后我会测试常见的情况。以 3/4/5 三角形为例:

    [TestMethod]
    public void TriangleConstructorWithFourPoints()
    {
        Point[] s = new []
        {
            new Point { x = 0, y = 0 },
            new Point { x = 4, y = 0 },
            new Point { x = 4, y = 3 }
        };
    
        Triangle target = new Triangle(s);
    
        Assert.IsTrue(target.Sides.Contains(3.0));
        Assert.IsTrue(target.Sides.Contains(4.0));
        Assert.IsTrue(target.Sides.Contains(5.0));
    }
    

    然后我会测试任何边缘条件,例如长度为 3 的数组,但数组中的一个点为空,(检查是否有适当的异常)或者任何两个点是否相同,依此类推。

    【讨论】:

      【解决方案4】:

      我假设你有一个Sides 属性,你可以断言从这里返回的值是它们应该的值。

      您可能还想稍微重构一下您的代码,在我看来,这 3 行代码几乎相同,但 Point 参数不同。

      另外,您粘贴的构造函数与示例测试中的构造函数不同。

      【讨论】:

      • 是的,我想我应该这样做(断言返回的值是应该的)。但是在这种情况下,我如何将它们实际返回给测试方法以便我可以检查它们?
      【解决方案5】:

      我想说的是,如果您遵循Eric Lippertrecommendations,那么您就不想拥有可变结构。现在,如果您在单元测试方面站在state verification 一边,您会得出结论,测试不可变对象没有意义,因为它们只能有一个状态。最好的情况,你能做到的最多就是测试构造函数没有做类似this.x = b的事情。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-03-23
        • 2017-09-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-09-14
        • 1970-01-01
        相关资源
        最近更新 更多