views:

327

answers:

1

I have a class which is designed to spin up a background thread, from which calls will be made into a manager. This manager will be mocked for the purposes of unit test. The relevant fragment of code is:

 MockRepository mocks = new MockRepository();
ICacheManager manager = mocks.CreateMock<ICacheManager>();

Expect.On(manager).Call(manager.CacheSize).Return(100);
mocks.ReplayAll();

CacheJanitor janitor = new CacheJanitor(manager);

// get janitor to do its stuff
// ...

mocks.VerifyAll();

The problem is that when verified we get two exceptions thrown - one on the test thread stating that a call to CacheSize was expected but didn't occur, and another on the background thread (within CacheJanitor) stating that a call to CacheSize occurred but was not expected.

Obviously the expectations have an affinity to the thread on which they are created. Does anyone know of a way to instruct Rhino Mocks to expect the call on a different thread (which doesn't even exist at the time that the expectations are defined)?

EDIT:

Forgot to mention the constraint that we are still on VS 2005 for the immediate future. Rhino Mocks version is 3.4 - I will try with 3.5, but the list of improvements don't seem to indicate any fixes in this area.

For the moment I will probably create my own mocked object for this series of tests and record the results within that, but would definately appreciate any solutions which allow me to cleanly achieve this using Rhino Mocks.

+1  A: 

Wow. That's crazy. I've used MoQ to do this sort of thing without an issue.

What version of Rhino are you using? You're using it in the pre-3.5 manner; perhaps this wouldn't be an issue with version 3.5?

Another alternative is to avoid verifying expectations on the mocks. (sorry, I'm not familiar with Rhino's syntax but it might be possible). Use a callback to set a local variable in the test function and verify on that variable.

In MoQ, I'd do it like this:

// Arrange
var called = false;
var mock = new Mock<SomeObject>();            

mock.Expect(x => SomeFunction()).Callback(() => called = true);            

var target = new MultithreadedTarget(mock.Object);            

// Act
target.DoSomethingThatCallsSomeFunctionOnAnotherThreadLol();            

// this part is a bit ugly
// spinlock for a bit to give the other thread a chance
var timeout = 0;
while(!called && timeout++ < 1000)
  Thread.Sleep(1);

// Assert
Assert.IsTrue(called);
Will
Unfortunately this only half works with RM. I still get the expectation violation on the background thread, because I have no way to tell RM to expect or ignore it. This exception is obviously thrown when the mocked property is accessed, not when VerifyAll is called.
Chris Ballard