【问题标题】:Rhino Mocks AAA syntax and thread safetyRhino Mocks AAA 语法和线程安全
【发布时间】:2010-11-19 11:03:10
【问题描述】:

我有一个问题,我的测试大部分通过但偶尔会失败。我认为这可能是一个线程问题,但我已经尝试过使用锁和睡眠等来尝试找出问题所在,但没有运气。我使用正确的语法吗?一段时间后,我将重新开始使用 Rhino。

这是我的测试的净化版本。正如我所说,它们在 4 次中工作了 3 次,但随后就繁荣了。

[TestFixture]
public class Tests
{
    [Test]
    public void ReprocessItems()
    {
        // Arrange
        Presenter presenter = new Presenter();

        Model model = new Model();

        model.Data.Add(new ViewModel(new Item { Id = 1 }) { IsSelected = true });
        model.Data.Add(new ViewModel(new Item { Id = 2 }) { IsSelected = true });
        model.Data.Add(new ViewModel(new Item { Id = 3 }) { IsSelected = false });
        model.Data.Add(new ViewModel(new Item { Id = 4 }) { IsSelected = false });

        presenter.Model = model;

        var gateway = MockRepository.GenerateStub<IGateway>();
        presenter.Gateway = gateway;

        // Act
        presenter.ReprocessItems();

        // Assert
        gateway.AssertWasCalled(o => o.ReprocessItem(1, presenter.ReprocessDone));
        gateway.AssertWasCalled(o => o.ReprocessItem(2, presenter.ReprocessDone));
    }

    [Test]
    public void ShowItemReferralCommentary()
    {
        // Arrange
        Presenter presenter = new Presenter();

        Model model = new Model();
        model.Data.Add(new ViewModel(new Item { Id = 1 }) { IsSelected = true });
        model.Data.Add(new ViewModel(new Item { Id = 2 }) { IsSelected = false });

        presenter.Model = model;

        var gateway = MockRepository.GenerateStub<IGateway>();
        presenter.Gateway = gateway;

        var view = MockRepository.GenerateStub<IView>();
        presenter.View = view;

        gateway.Stub(x => x.RequestItemCommentary(1)).Return("This is some commentary");

        // Act
        presenter.ShowItemReferralCommentary();

        // Assert
        gateway.AssertWasCalled(o => o.RequestItemCommentary(1));

        view.AssertWasCalled(o => o.ShowMessageBox("This is some commentary", "Referral Commentary"));
    }

    [Test]
    public void AcceptSelectedItems()
    {
        // Arrange
        Presenter presenter = new Presenter();

        Model model = new Model();
        model.Data.Add(new ViewModel(new Item { Id = 1 }) { IsSelected = false });
        model.Data.Add(new ViewModel(new Item { Id = 2 }) { IsSelected = false });
        model.Data.Add(new ViewModel(new Item { Id = 3 }) { IsSelected = true });
        model.Data.Add(new ViewModel(new Item { Id = 4 }) { IsSelected = true });

        presenter.Model = model;

        var gateway = MockRepository.GenerateStub<IGateway>();
        presenter.Gateway = gateway;

        // Act
        presenter.AcceptSelectedItems();

        // Assert
        gateway.AssertWasCalled(o => o.AcceptItem(3, presenter.AcceptCompleted));
        gateway.AssertWasCalled(o => o.AcceptItem(4, presenter.AcceptCompleted));
    }
}

编辑:** 根据下面的评论,我通过添加 Thread.Sleep(500); 暂时解决了这个问题;在每个断言之前。 Thread.Sleeps 通常是一种代码气味,我想将其锁定,但我试图做到 sloppy 务实。如果您有更好的方法,请告诉我。

【问题讨论】:

  • 线程方法有哪些?
  • ReprocessItem 和 ReprocessDone 之类的东西是回调。

标签: c# unit-testing rhino-mocks


【解决方案1】:

问题是您可能会在测试方法结束时放置断言,而子线程可能已经完成了他们的工作,也可能没有。在你看来,这几乎是随机的。

您可以做的,也是我在测试线程方法时所做的,就是使用同步对象,例如 ManualResetEvent。您在测试方法开始时将其重置为 false:

var wait = new ManualResetEvent(false);

然后,当你的模拟被正在测试的对象调用时,你设置它的状态:

Expect.Call(() => yourMock.yourMethod(whatever)).WhenCalled(x => wait.Set() );

现在,在你的断言块代码之前,你写一些类似的东西

Assert(wait.WaitOne(timeoutOfYourChoice));

这将为辅助线程留出足够的时间来完成它们的工作。

【讨论】:

  • 我试着把它放进去,但有什么地方坏了。如果我在断言之前输入一个简单的 Thread.Sleep(500) ,它就可以工作。目前还不够理想。不过我会研究这个。 ManualResetEvent 可能是赢家。感谢您的提示。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-01-08
  • 2010-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-01-29
相关资源
最近更新 更多