我是否应该使用不同的方法为相同的行为创建不同的测试?

Should I create different tests for the same behavior using different methods?

提问人:Pavel Dubsky 提问时间:8/17/2014 更新时间:8/17/2014 访问量:28

问:

我有这样的代码:

public class Foo
{
    ...

    public override bool EqualsTo(object obj)
    {
        ...
    }

    public static bool operator==(Foo left, Foo right)
    {
        ...
    }

    public static bool operator!=(Foo left, Foo right)
    {
        ...
    }
}

此代码示例的主要目的是说明类可以有多种方式来执行相同的操作,例如检查对象的相等性。所以方法和运算符 和 只是为了简单起见。它可以是任何不同的方法集。主要的一点是,有多种方法可以获得相同的行为。EqualsTo==!=

我有两种单元测试的变体:

变式1:

[TestClass]
public class FooTest
{
    [TestMethod]
    public void ShouldCheckEqualityWhenObjectsEqual()
    {
        var foo1 = new Foo(1);
        var foo2 = new Foo(1);

        Assert.IsTrue(foo1.EqualsTo(foo2));
        Assert.IsTrue(foo2.EqualsTo(foo1));
        Assert.IsTrue(foo1 == foo2);
        Assert.IsTrue(foo2 == foo1);
        Assert.IsFalse(foo1 != foo2);
        Assert.IsFalse(foo2 != foo1);
    }

    [TestMethod]
    public void ShouldCheckEqualityWhenObjectsNotEqual()
    {
        var foo1 = new Foo(1);
        var foo2 = new Foo(2);

        Assert.IsFalse(foo1.EqualsTo(foo2));
        Assert.IsFalse(foo2.EqualsTo(foo1));
        Assert.IsTrue(foo1 == foo2);
        Assert.IsTrue(foo2 == foo1);
        Assert.IsTrue(foo1 != foo2);
        Assert.IsTrue(foo2 != foo1);
    }
}

变式2:

[TestClass]
public class FooTest
{
    [TestMethod]
    public void ShouldCheckEqualityWhenObjectsEqualUsingMethod()
    {
        var foo1 = new Foo(1);
        var foo2 = new Foo(1);

        Assert.IsTrue(foo1.EqualsTo(foo2));
        Assert.IsTrue(foo2.EqualsTo(foo1));
    }

    [TestMethod]
    public void ShouldCheckEqualityWhenObjectsEqualUsingEqualityOperator()
    {
        var foo1 = new Foo(1);
        var foo2 = new Foo(1);

        Assert.IsTrue(foo1 == foo2);
        Assert.IsTrue(foo2 == foo1);
    }


    [TestMethod]
    public void ShouldCheckEqualityWhenObjectsEqualUsingInequalityOperator()
    {
        var foo1 = new Foo(1);
        var foo2 = new Foo(1);

        Assert.IsFalse(foo1 != foo2);
        Assert.IsFalse(foo2 != foo1);
    }

    [TestMethod]
    public void ShouldCheckEqualityWhenObjectsNotEqualUsingMethod()
    {
        var foo1 = new Foo(1);
        var foo2 = new Foo(2);

        Assert.IsFalse(foo1.EqualsTo(foo2));
        Assert.IsFalse(foo2.EqualsTo(foo1));
    }

    [TestMethod]
    public void ShouldCheckEqualityWhenObjectsNotEqualUsingEqualityOperator()
    {
        var foo1 = new Foo(1);
        var foo2 = new Foo(2);

        Assert.IsTrue(foo1 == foo2);
        Assert.IsTrue(foo2 == foo1);
    }

    [TestMethod]
    public void ShouldCheckEqualityWhenObjectsNotEqualUsingInequalityOperator()
    {
        var foo1 = new Foo(1);
        var foo2 = new Foo(2);

        Assert.IsTrue(foo1 != foo2);
        Assert.IsTrue(foo2 != foo1);
    }
}

对我来说,变体 1 更短且易于理解,但变体 2 在完成的内容和完成方式方面更加精确,并且具有更多的样板代码,例如数据初始化和设置。我想知道这两种变体中哪一种更受欢迎。或者也许有比这些更好的变体。

相等性测试仅用于简单起见,并且数据设置和初始化可能会更长。

另一个例子:

public class Bar
{
    ...
    public int this[short index] { ... }
    public int this[int index] { ... }
    public int this[long index] { ... }
}

我应该为每个索引器创建单独的测试,还是可以在一个测试中针对同一对象测试它们,假设它们的行为应该相同。

单元测试

评论


答:

1赞 Lasse V. Karlsen 8/17/2014 #1

是的,你应该这样做,我也会投票支持结束你的问题,以征求意见。

原因如下。

一个测试应该只测试一件事。

1 件事。

如果你想测试该方法是否有效,那就是 1 个测试。Equals

如果要测试运算符是否正常工作,则这是另一个测试。==

有些人可能认为这两者是相同的,特别是如果其中一个方法调用另一个方法。

因此,我投票决定结束这个问题,以征求意见。

但在我看来,每次测试应该只测试 1 件事。如果有多个方法实现相同的概念,则每个方法都需要进行自己的测试。

最后,你希望一个失败的测试能具体告诉你哪里出了问题。如果这个“具体”可以是任意数量的方法,那么你的测试就太宽泛了。

但这是我的看法。