mik*_*dev 3 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
}
Run Code Online (Sandbox Code Playgroud)
虽然测试完全符合我的要求,但我不禁觉得自己做错了什么.
在相关的说明中,DiceRoll类中还包含其他信息,但我的问题是关于在单元测试中循环,所以我把它留下来让它更清晰
这种方法的问题在于您依赖于随机行为.有可能在300卷内,所需状态永远不会出现,并且单元测试失败,而测试代码没有错误.
我将研究通过接口(例如"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
}
}
Run Code Online (Sandbox Code Playgroud)
......并在您的单元测试项目中:
internal class MockedDiceRoller : IDiceRoller
{
public int Value { get; set; }
public int GetValue(int lowerBound, int upperBound)
{
return this.Value;
}
}
Run Code Online (Sandbox Code Playgroud)
现在,在您的单元测试中,您可以创建一个MockedDiceRoller,设置您希望骰子获得的值,在Dice类中设置模拟骰子滚轮,滚动并验证该行为:
MockedDiceRoller diceRoller = new MockedDiceRoller();
diceRoller.Value = 20;
Dice.SetDiceRoller(diceRoller);
Dice.Roll(1, 20);
Assert.IsTrue(Dice.IsCritical);
Run Code Online (Sandbox Code Playgroud)