我的单元测试对于不同的输入有多余?

时间:2015-03-05 14:16:59

标签: c# unit-testing tdd

所以我是单位测试的新手(很晚才到派对,但我至少在这里)。我将几个ASP.NET MVC Web应用程序使用的一些常用代码提取到一个或多个类库中。我现在正在为一些代码编写单元测试......其中大部分实际上是IDataReader上的扩展方法(意图用于对抗OdbcDataReader)。在下面的代码中,扩展方法扩展了对象,因此我可以实际编写单元测试。我曾尝试使用Moq来模拟IDataReader来测试扩展方法,但我已经读过,这是不可能的。在任何情况下,这不是真正的问题所在。

这是我的问题。我有一个名为" GetSafeDecimal"的方法。意图是它将被用作:

dr.getSafeDecimal(dr["FieldValue"])

该方法定义如下:

   public static decimal GetSafeDecimal(this object rdr, object value)
    {
        decimal result = 0;
        decimal temp = -1;

            if (value == null || value is DBNull)
                result = 0;
            else if (decimal.TryParse(value.ToString(), out temp))
                result = temp;
            else if (value is string)
            {
                String s = Convert.ToString(value) ?? string.Empty;
                s = s.Replace(" ", "");
                if (String.IsNullOrEmpty(s) ||
                    !decimal.TryParse(s, out temp))
                {
                    result = 0;
                }
                else
                {
                    result = decimal.Parse(s);
                }
            }
        return result;
    }

我的实际问题:我在单元测试中看到了大量的重复。设置并不难。我只是为我测试的每个输入写一个单元测试。这是"正确"单元测试的方法?

以下是我对上述方法的一些单元测试:

[TestMethod]
    public void GetSafeDecimalNullReturns0()
    {
        decimal result = "".GetSafeDecimal(null);
        Assert.AreEqual(result , 0);  
    }

    [TestMethod]
    public void GetSafeDecimalIntReturnsDecimalValue()
    {
        decimal result = "".GetSafeDecimal(5);
        Assert.AreEqual(result, 5);
    }

    [TestMethod]
    public void GetSafeDecimalStringReturns0()
    {
        decimal result = "".GetSafeDecimal("asdf");
        Assert.AreEqual(result, 0);
    }

    [TestMethod]
    public void GetSafeDecimalStringSpecialCharactersReturns0()
    {
        decimal result = "".GetSafeDecimal("a_ s)@#$df");
        Assert.AreEqual(result, 0);
    }

    [TestMethod]
    public void GetSafeDecimalIntStringReturns0()
    {
        decimal result = "".GetSafeDecimal("2 3 5");
        Assert.AreEqual(result, 235);
    }

    [TestMethod]
    public void GetSafeDecimalDecimalReturnsDecimal()
    {
        decimal result = "".GetSafeDecimal(3.14M);
        Assert.AreEqual(result, 3.14M);
    }

    [TestMethod]
    public void GetSafeDecimalDoubleReturnsDecimal()
    {
        decimal result = "".GetSafeDecimal(3.14d);
        Assert.AreEqual(result, 3.14M);
    }

@塞巴斯蒂安的解决方案现场点亮了。切换到nunit后,我的测试现在看起来像:

public class SafeDecimalTestData
{
    public static IEnumerable TestCases
    {
        get
        {
            yield return new TestCaseData(null).Returns(0);
            yield return new TestCaseData(5).Returns(5);
            yield return new TestCaseData("asdf").Returns(0);
            yield return new TestCaseData("a_ s)@#$df").Returns(0);
            yield return new TestCaseData("2 3 5").Returns(235);
            yield return new TestCaseData(3.14m).Returns(3.14m);
            yield return new TestCaseData(3.14m).Returns(3.14d);
            yield return new TestCaseData(new DateTime(2015,1,1)).Returns(0);
        }
    }
}


    [Test, TestCaseSource(typeof(SafeDecimalTestData), "TestCases")]
    public decimal GetSafeDecimalTestInputs(object input)
    {
        return "".GetSafeDecimal(input);
    }

我以这种方式编写测试而不是仅使用TestCase属性,因为测试不允许我使用3.14d,3.14m或DateTime等值。我想要一个解决方案,无论我测试的数据类型如何,我都可以对所有测试使用。该解决方案来自NUnit文档:

TestCaseSourceAttribute

1 个答案:

答案 0 :(得分:1)

在许多单元测试框架中,有一个特殊的构造,允许您定义一个测试方法并提供几个测试用例。例如,在NUnit中,您拥有TestCase属性。