views:

385

answers:

2

When executing the second line of this code Rhino Mocks throws an InvalidOperationException with a message "This action is invalid when the mock object is in replay state"

var mockScanner = MockRepository.GenerateMock<PortScanner>(null);
        mockScanner.Expect((scanner => { scanner.Scan(null, null); }));

Stepping through the code in a debugger one can see the debugger run the method defined in the class and directly after control leaves this method the exception occurs.

This similar code in another test does work without issue

var mockView = MockRepository.GenerateMock<IScanView>(null);
        mockView.Expect(view => { view.Close(); });
        var controller = new ScanController(mockView);
        controller.Exit();
        mockView.VerifyAllExpectations();

The only difference that I can think of that might be of any consequense between theese two tests is that Exit is a member on an interface while Scan is a virtual member on a class

What am I missing?

Update
Further exploration has indicated that this is related to the way Rhino handles virtual methods. I am focusing mmy study of the documentation here now

A: 

What happens if you remove the extra set of parentheses from the first expression?

var mockScanner = MockRepository.GenerateMock<PortScanner>(null);
mockScanner.Expect( scanner => { scanner.Scan(null, null); } );
tvanfosson
Then my syntax gets a little cleamer (thanks :) ), unfortunatly my test still throws
Crippledsmurf
Any significance to the null parameter in the constructor. What happens if you pass in a valid object there instead of null?
tvanfosson
They are normally IPAddress objects that get passed in by a real controller. They are null because it's more convient to type than anything else (it's 3:47 AM) but right now that method's an empty stub which doesn't use the parameters anywhereI've tried them with real parameter values too, I still get the same exceptionI think this is a sign that I am officially too old to be coding this late now
Crippledsmurf
+4  A: 

The exception was caused because Rhino Mocks did not have the required level of access to the type in order to mock it properly. Granting internal access to the Rhino Mocks assembly using InternalsVisibleTo solved the problem.

It's noteworthy that this does not affect interfaces. I believe the reason for this is because the mocking framework needs to override the implementation on a class where there is none on an interface.

Crippledsmurf
I just read about doing this today. The documentation link to the Rhino Mocks wiki entry is: http://ayende.com/Wiki/(S(vcy2bn55h5cja0vsedn14y45))/Rhino+Mocks+-+Internal+Methods.ashx
Ogre Psalm33