【问题标题】:TestCaseSource in N-UnitN-Unit 中的 TestCaseSource
【发布时间】:2012-10-10 14:30:07
【问题描述】:

我正在编写一些 N 单元测试,但遇到了一点困难。我正在尝试在我的代码中将测试连接到 TestCaseSource,但它似乎没有正确构造对象。

这是我的测试方法:

    [Test, TestCaseSource(typeof(TestCaseStuff), "GetTestCases", Category = "Release")]
    public void WithdrawMoney(TestCaseStuff tc)
    {
        double newBalance = AccountBalance - tc.amt;
        if (newBalance < 0)
        {
            Assert.Fail(String.Format("You can't withdraw {0}! You've maxed" +
                "out your bank account.", tc.amt.ToString("C2")));
        }

        AccountBalance = newBalance;
        Assert.Pass(String.Format("Your new balance is {0}.", 
        (AccountBalance).ToString("C2")));
    }

还有我的TestCaseSource

public class TestCaseStuff
{
    public double amt { get; set; }

    public TestCaseStuff()
    {
        Random rnd = new Random();
        this.amt = rnd.Next(0, 20);
    }

    [Category("Release")]
    public IEnumerable<TestCaseData> GetTestCases()
    {
        for (int i = 0; i < 500; i++)
        {
            yield return new TestCaseData(this);
        }
    }
}

这主要用作概念证明,因此当需要编写具有复杂对象的实际测试时,我会知道我可以像上面那样编写一个循环并将随机值放入我的对象中。但是,返回到我的测试方法的 TestCaseStuff 的每个实例都是相同的。

更新:

下面的答案是正确的。当我将它传递给 N-Units TestCaseData 对象时,我假设(错误地)它只会按值传递该实例。显然,它是通过引用完成的,这就是为什么值总是相同的。

最重要的是,我错误地使用了Random 类。这不是我通常处理的事情,但我没有正确阅读它。正如下面链接中所解释的,当使用Random 及其默认构造函数时,种子值是从系统时钟派生的。因此,如果您快速连续实例化多个 Random 对象,它们将共享相同的默认种子值并生成相同的值。

因此,由于这些发展,我的代码现在变为:

public class TestCaseStuff
{
    public double amt { get; set; }
    private static readonly Random rnd = new Random();

    public TestCaseStuff()
    {
        this.amt = rnd.Next(0, 20);
    }

    [Category("Release")]
    public IEnumerable<TestCaseData> GetTestCases()
    {
        for (int i = 0; i < 500; i++)
        {
            yield return new TestCaseData(new TestCaseStuff());
        }
    }

}

【问题讨论】:

    标签: c# .net unit-testing nunit testcasesource


    【解决方案1】:

    上述代码只会实例化TestCaseSource 的一份副本,并继续提供相同的值。

    如果打算在每个循环中生成一个随机数,我认为您应该创建 Random 对象的静态实例,并在每次创建新的 TestCaseStuff 对象时从中生成一个数字。

    我会像这样重写 TestCaseStuff:

    public class TestCaseStuff
    {
        // Static instance of a random number generator.
        private static readonly Random RNG = new Random();
    
        public double amt { get; set; }
    
        public TestCaseStuff()
        {
            this.amt = RNG.Next(0, 20);
        }
    
        [Category("Release")]
        public IEnumerable<TestCaseData> GetTestCases()
        {
            for (int i = 0; i < 500; i++)
            {
                // NOTE: You need to create a new instance here.
                yield return new TestCaseData(new TestCaseStuff());
            }
        }
    }
    

    【讨论】:

    • 是的,这就是我最终所做的。当我传入this时,我以为TestCaseData会有自己的TestCaseStuff副本,但我显然错了。
    【解决方案2】:

    您每次调用时都会创建一个新的 Random 实例:

    yield return new TestCaseData(this);
    

    尝试将其移出循环,您应该会开始获取随机值。

    发现这篇文章解释得很好! How do I seed a random class to avoid getting duplicate random values

    【讨论】:

    • 很好,但问题只解决了一半。不过,仍然值得一票。谢谢!
    猜你喜欢
    • 2018-10-07
    • 2013-04-27
    • 2021-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-10
    相关资源
    最近更新 更多