I have an issue where my tests pass most of the time but occasionally fail. I think it might be a threading issue, but I've experimented with locks and sleeps etc to try and find where the problems lies with no luck. Am I using the correct syntax? I'm getting back into using Rhino after a while away.
Here's a sanitised version of my tests. As I say, they work 3 out of 4 times, but then boom.
[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));
}
}
EDIT: ** As per a comment below, I have temporarily solved this by adding a Thread.Sleep(500); before each assert. Thread.Sleeps are generally a code smell, and I'd like to lock it down but I'm trying to be sloppy pragmatic. Please do let me know if you have a better way.
The problem is that you could get at the end of the test methods, where you placed the assertions, while the children thread could have done their job or not. To your point of view, it's almost random.
What you could do, and that's what I do when I test threaded methods, is to use a synchronization object such as ManualResetEvent. You reset it to false at the test methods beginning:
var wait = new ManualResetEvent(false);
Then, when your mock is invoked by the object being tested, you set its status:
Expect.Call(() => yourMock.yourMethod(whatever)).WhenCalled(x => wait.Set() );
Now, before your assertion block code, you write something like
Assert(wait.WaitOne(timeoutOfYourChoice));
This will leave secondary thread enough time to finish their work.
精彩评论