8

我创建了一个 NUnit Theory 来帮助我测试一些代码。被测试的实际代码对于这个问题并不像我用来测试它的数据那么重要。即,24 小时制的小时和分钟。

我以这种方式编写我的夹具是为了利用这些特性并符合 NUnit 2.6 Theory 特性中的限制。特别是,我觉得我必须创建诸如 Hour 和 Minute 之类的类,以解决 Datapoints 按确切类型与参数匹配的特性。

[TestFixture]
public class TimeWindowParserTheoryFixture
{
    public class Hour
    {
        public int Value;
    }

    public class Minute
    {
        public int Value;
        public string AsString { get { return Value.ToString("00"); } }
    }

    [Datapoints]
    public IEnumerable<Hour> Hours
    {
        get
        {
            return Enumerable
                .Range(0, 25)
                .Select(v => new Hour() { Value = v })
                .Union(Enumerable.Repeat((Hour)null, 1));
        }
    }

    [Datapoints]
    public IEnumerable<Minute> Minutes
    {
        get
        {
            return Enumerable
                .Range(0, 60)
                .Select(v => new Minute() { Value = v })
                .Union(Enumerable.Repeat((Minute)null, 1));
        }
    }

    [Datapoints]
    public IEnumerable<string> Separators
    {
        get { return new[] { " ", "-" }; }
    }

    [Theory]
    public void ValidHours(Hour startHour,
        Minute startMinute,
        Hour endHour,
        Minute endMinute,
        string separator)
    {
        Assume.That(startHour != null);
        Assume.That(endHour != null);

        var parser = new TimeWindowParser();
        var startMinutesString = String.Format("{0}{1}", startMinute == null ? "" : ":", startMinute == null ? "" : startMinute.AsString);
        var endMinutesString = String.Format("{0}{1}", endMinute == null ? "" : ":", endMinute == null ? "" : endMinute.AsString);
        var pattern = String.Format("{0}{1}{2}{3}{4}{5}{6}", startHour, startMinutesString, "", separator, endHour, endMinutesString, "");
        //Console.WriteLine(pattern);
        var result = parser.Parse(pattern);
        Assert.That(result, Is.Not.Null);
        Assert.That(result.Start, Is.EqualTo(startHour));
        Assert.That(result.End, Is.EqualTo(endHour));
    }
}

我发现在 NUnit 的默认组合逻辑期间生成的数据集的大小导致数据集太大,以至于我的内存不足。我设置测试和数据的方式似乎不是问题,但显然是这样,所以我正在寻求有关如何以不同方式思考这个问题的建议。这是我得到的 OutOfMemoryException 堆栈跟踪。

System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown.
at System.Text.StringBuilder.ExpandByABlock(Int32 minBlockCharCount)
at System.Text.StringBuilder.Append(Char* value, Int32 valueCount)
at System.Text.StringBuilder.AppendHelper(String value)
at System.Text.StringBuilder.Append(String value)
at NUnit.Core.MethodHelper.GetDisplayName(MethodInfo method, Object[] arglist)
at NUnit.Core.Builders.NUnitTestCaseBuilder.BuildSingleTestMethod(MethodInfo method, Test parentSuite, ParameterSet parms)

此异常本身很奇怪,因为它似乎是通过简单地尝试获取 Test 方法的名称来生成的(请参阅 GetDisplayName)。我不确定这是否是一个错误(已知或其他)。顺便说一句,当我使用参数化测试中使用的实验性较少的 Range 和 Value 属性重新编写此夹具时,我得到了一个非常相似的 OOM 异常。

4

1 回答 1

13

你的问题是关于使用理论的机制,但我想先谈谈“理论理论”,然后我会回到实现细节。

理论的理论

如果你有一个理论开始,你应该只使用一个理论。否则,您只是使用数据点来驱动传统的示例驱动测试。“有一个理论”是指有一些一般性的真理陈述,你想通过一些输入来证明它。一般来说,理论(代码)将遍历可能的输入并过滤掉任何不符合您假设的内容。一个好的理论的例子是:对于任何正实数,平方根乘以自身将得到相同的数字。”

查看您的测试,我无法弄清楚您的 Theory 试图证明什么理论。它看起来就像一个标准的参数化测试,除了您使用的是 DataPoints。您需要做的唯一假设是分钟不为空,这很奇怪,因为您首先提供了分钟。

底线:我不认为这是对理论的一个很好的使用。

力学

您正在生成 24*24*60*60*2 数据点。这是一大堆数据。您是否有任何理由相信您的解析算法可能适用于 - 比如说 - 24:13 但在 24:14 时失败?

确实,数据点是组合使用的,如果成对使用可能会更好。但请记住,DataPoints 只是将数据投入理论的众多方法之一。这个想法是理论应该处理你给他们的任何数据。

选择

我会把它写成一个测试,因为我想不出任何关于你的解析器或解析器的理论都适用。我只会提供测试有效数据,可能使用 TestCaseSourceAttribute 指向生成有效字符串的方法或简单地指向一个大字符串数组。我会有另一个处理各种无效数据的测试。

查理

于 2013-11-05T01:53:20.917 回答