在TestFixtureSetup中创建线程会导致测试随机失败

时间:2013-12-23 01:41:44

标签: c# multithreading unit-testing mocking

我想测试一个永远运行的游戏循环,直到用户退出或死亡,然后显示一条消息。

这样的事情:

    [TestFixtureSetUp]
    public void SetupMethods()
    {
        _input = new Mock<IInput>();
        _input.SetupProperty(i => i.QuitKey, 'q');
        _messenger = new Mock<IMessenger>();
        _grid = new Mock<IGrid>();
        _clock = new Mock<IClock>();
        _game = new Game(_input.Object, _messenger.Object, _grid.Object, _clock.Object);
    }

    [Test]
    public void should_loop_until_player_quits_then_show_confirmation()
    {
        _input.Setup(g => g.ReadKey()).Returns(_input.Object.QuitKey);

        _messenger.Verify(m => m.SendMessage("Are you sure?"));
    }

    [Test]
    public void should_loop_until_player_dies_then_show_game_over_message()
    {
        _game.IsGameOver = true;

        _messenger.Verify(m => m.SendMessage("Game Over"));
    }

Game班级里面

    public void GameLoop()
    {
        //gets player input
        while (ReadKey() != _input.QuitKey && !IsGameOver)
        {
            //waits for clock
            if (_clock.TimeElapsed % 1000 == 0)
            {
                //logic
            }               
        }

        if (IsGameOver)
        {
            _messenger.SendMessage("Game Over");
        }
        else
        {
            _messenger.SendMessage("Are you sure?");
        }
    }

允许循环运行我发现创建一个单独的线程可以工作,并且不会挂起测试。但是,当我将新的线程代码放入安装程序时,如果我Test All(我有大约5或6),测试会随机失败。如果我单独进行每项测试,那就没关系了。

    [SetUp]
    public void SetupTest()
    {
        new Thread(() =>
        {
            Thread.CurrentThread.IsBackground = true;
            _game.GameLoop();
        }).Start();
    }

我做错了什么?

1 个答案:

答案 0 :(得分:0)

您的测试尚无定论,因为它们是

  • 以随机顺序运行
  • 在您的测试中,您在模拟上设置了各种返回值

结果是:你永远不会完全知道你的游戏循环看到了什么值。

为了解决这个问题,你必须在每次测试的基础上重新设置你的所有模拟(即SetUp,而不是TestFixtureSetUp),因为据我所知,Moq没有'对于Mocks来说有类似Clear()方法的东西。

编辑
另外,您必须确保将变量正确传递给线程。试试这个:

[SetUp]
public void SetupTest()
{
    _input = new Mock<IInput>();
    _input.SetupProperty(i => i.QuitKey, 'q');
    _messenger = new Mock<IMessenger>();
    _grid = new Mock<IGrid>();
    _clock = new Mock<IClock>();

    new Thread(() =>
    {
        Thread.CurrentThread.IsBackground = true;

        IInput input = _input.Object;
        IMessenger messenger = _messenger.Object;
        IGrid grid = _grid.Object;
        IClock clock = _clock.Object;

        _game = new Game(input, messenger, grid, clock);
        _game.GameLoop();
    }).Start();
}