c# - 在单元测试中循环不好?

标签 c# unit-testing loops dice

我有一个依赖随机掷骰子的单元测试。我掷了一个 20 面的骰子,如果值为 20,则算作一次重击。

我现在正在做的是将 20 面的骰子最多滚动 300 次。如果这些掷骰中有任何一个是 20,那么我就知道我受到了重击。

代码如下:

public class DiceRoll
{
    public int Value { get; set; }
    public bool IsCritical { get; set; }

    // code here that sets IsCritical to true if "Value" gets set to 20
}

[Test]
public void DiceCanRollCriticalStrikes()
{
    bool IsSuccessful = false;
    DiceRoll diceRoll = new DiceRoll();

    for(int i=0; i<300; i++)
    {
        diceRoll.Value = Dice.Roll(1, 20); // roll 20 sided die once
        if(diceRoll.Value == 20 && diceRoll.IsCritical)
        {
            IsSuccessful = true;
            break;
        }
    }

    if(IsSuccessful)
        // test passed
    else
        // test failed 
}

虽然测试完全符合我的要求,但我还是忍不住觉得自己做错了什么。

在相关说明中,DiceRoll 类中还有其他信息,但我的问题具体是关于单元测试中的循环,所以我将其省略以使其更清楚

最佳答案

这种方法的问题在于您依赖于随机行为。有可能在300 rolls之内,想要的状态一直没有出现,单元测试失败,而没有被测试的代码有错。

我会考虑通过接口(interface)(例如“IDiceRoller”)从 Dice 类中提取掷骰子逻辑。然后您可以在您的应用程序中实现随机骰子滚筒,并在您的单元测试项目中实现另一个骰子滚筒。这个遗嘱总是可以返回一个预定义的值。这样您就可以为特定的骰子值编写测试,而不必诉诸循环并希望值出现。

示例:

(您应用程序中的代码)

public interface IDiceRoller
{
    int GetValue(int lowerBound, int upperBound);
}

public class DefaultRoller : IDiceRoller
{
    public int GetValue(int lowerBound, int upperBound)
    {
        // return random value between lowerBound and upperBound
    }
}

public class Dice
{
    private static IDiceRoller _diceRoller = new DefaultRoller();

    public static void SetDiceRoller(IDiceRoller diceRoller)
    {
        _diceRoller = diceRoller;
    }

    public static void Roll(int lowerBound, int upperBound)
    {
        int newValue = _diceRoller.GetValue(lowerBound, upperBound);
        // use newValue
    }
}

...在您的单元测试项目中:

internal class MockedDiceRoller : IDiceRoller
{
    public int Value { get; set; }

    public int GetValue(int lowerBound, int upperBound)
    {
        return this.Value;
    }
}

现在,在您的单元测试中,您可以创建一个 MockedDiceRoller,设置您希望骰子获得的值,在 Dice 类中设置模拟骰子滚轮,滚动并验证该行为:

MockedDiceRoller diceRoller = new MockedDiceRoller();
diceRoller.Value = 20;
Dice.SetDiceRoller(diceRoller);

Dice.Roll(1, 20);
Assert.IsTrue(Dice.IsCritical);

关于c# - 在单元测试中循环不好?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2126342/

相关文章:

c# - 匿名类型 LinQ - 检查空值 - 异常

c# - 从给定线程获取 SynchronizationContext

c# - 如何解决 "The method ' Skip' 仅支持 LINQ to Entities 中的排序输入。”

Javascript 模块模式 - 如何揭示所有方法?

java - Python 模拟和单元测试最佳实践

java - "for"循环没有按照我想要的方式迭代

javascript - 暂停 for 循环的迭代?

java - 我的循环出了什么问题?不断收到 NoSuchElementException

c# - WPF:如何从项目控件中查找数据模板中的元素

c++ - 使用 googletest 一次为多个测试模块运行单元测试