如何设计NUnit理论?

dkm*_*dkm 7 theory nunit out-of-memory datapoint

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

我用这种方式编写了夹具,以便利用这些特性并符合NUnit 2.6 Theory特性中的限制.特别是,我觉得我必须创建像小时和分钟这样的类,以便解决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));
    }
}
Run Code Online (Sandbox Code Playgroud)

我发现在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)
Run Code Online (Sandbox Code Playgroud)

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

Cha*_*lie 11

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

理论理论

如果你有一个理论可以开始,你应该只使用一个理论.否则,您只是使用Datapoints来推动传统的示例驱动测试.通过"有一个理论",我的意思是有一些一般性的真实陈述,你想通过一些输入来证明.通常理论(代码)将通过可能的输入并过滤掉任何不符合您的假设的东西.一个好的理论的一个例子是:对于任何正实数,平方根乘以其自身将给出相同的数字."

看看你的考试,我无法弄清楚你的理论想要证明什么理论.它看起来就像一个标准的参数化测试,除了你正在使用DataPoints.您需要做的唯一假设是minuts不为null,这是奇怪的,因为您首先提供分钟.

一句话:我认为这不是一个很好用的理论.

力学

您正在生成24*24*60*60*2 DataPoints.这是很多数据.你是否有理由相信你的解析算法可能适用于 - 比如说24:13但是24:14失败了?

确实,Datapoints是组合使用的,如果它们成对使用可能会更好.但请记住,DataPoints只是在Theory中抛出数据的众多方法之一.这个想法是理论应该处理你给他们的任何数据.

备选

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

查理