Rhino Mocks AAA语法和线程安全

Iai*_*der 1 c# unit-testing rhino-mocks

我有一个问题,我的测试通过大部分时间但偶尔会失败.我认为这可能是一个线程问题,但我已经尝试过锁定和睡眠等尝试找到问题所在而没有运气.我使用正确的语法吗?过了一会儿我才回到使用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));
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑:**根据下面的评论,我通过添加Thread.Sleep(500)暂时解决了这个问题.在每个断言之前.Thread.Sleeps通常是一种代码味道,我想把它锁定,但我正试图邋p实用.如果你有更好的方法,请告诉我.

Sim*_*one 5

问题是你可以在测试方法结束时放置断言,而子线程可以完成它们的工作.就你的观点而言,它几乎是随机的.

你可以做什么,而我在测试线程方法时所做的就是使用一个同步对象,如ManualResetEvent.您在测试方法开始时将其重置为false:

var wait = new ManualResetEvent(false);
Run Code Online (Sandbox Code Playgroud)

然后,当被测对象调用mock时,设置其状态:

Expect.Call(() => yourMock.yourMethod(whatever)).WhenCalled(x => wait.Set() );
Run Code Online (Sandbox Code Playgroud)

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

Assert(wait.WaitOne(timeoutOfYourChoice));
Run Code Online (Sandbox Code Playgroud)

这将使次要线程有足够的时间来完成他们的工作.