Search code examples
c#rhino-mocks

How do we make lambda function execute in method that is part of a Rhino Mock object?


I'm currently creating some unit tests with rhino mocks and I have a test that looks like below. However I keep getting this error message,

IOsgController.AddWindow(Whiteboard.Model.OsgWindowProps); Expected #1, Actual #0.

Which is due to the lambda function not being executed in _dispatcher.BeginInvoke(()=>_osgController.AddWindow). How do I make this Action get executed in my unit tests?

public void the_load_command_is_triggered_which_executes_the_load_control_method()
{
       // arrange
        IOsgController osgController = MockRepository.GenerateMock<IOsgController>();
        IDispatcher dispatcher = MockRepository.GenerateMock<IDispatcher>();
        Action action = osgController.AddWindow;
        OsgViewModel osgViewModel = new OsgViewModel(osgController, dispatcher);

        // dispatcher and add window should be called in LoadControl
        dispatcher.Expect(d => d.BeginInvoke(action)).WhenCalled(i => action());
        osgController.Expect(x => x.AddWindow());

        // act
        osgViewModel.LoadCommand.Execute(new object());

        // assert
        osgController.VerifyAllExpectations();
}

Class under test is:

public class OsgViewModel : ViewModelBase
{
    private readonly IOsgController _osgController;
    private readonly IDispatcher _dispatcher;

    public OsgViewModel(IOsgController osgController, IDispatcher dispatcher)
    {
        _osgController = osgController;
        _dispatcher = dispatcher;
        LoadCommand = new RelayCommand(LoadControl);
    }

    public ICommand LoadCommand { get; set; }

    public void LoadControl()
    {
        // lambda is not being executed in unit test.
        _dispatcher.BeginInvoke(
            () => _osgController.AddWindow());
    }
}

Solution

  • The reason why lambda function is not being executed in the test is the following:

    There are 2 lambdas:

    1. The one declared in test method:

      Action action = osgController.AddWindow;
      
    2. The other one declared in the class under test:

      () => _osgController.AddWindow()
      

    They do exactly the same but they are different.
    That is why setup for dispatcher.Expect(d => d.BeginInvoke(action)) doesn't match to the actual action passed to BeginInvoke(). As a result WhenCalled() argument is not being triggered.

    The one of solutions is to setup the stub for dispatcher.BeginInvoke() which accepts any action and just executes it:

     dispatcher
        .Stub(d => d.BeginInvoke(Arg<Action>.Is.Anything))
        .WhenCalled(opt => ((Action)(opt.Arguments[0]))());
    

    Also, Do() handler can be used instead of WhenCalled() here. Then arguments cast isn't required:

     dispatcher
        .Stub(d => d.BeginInvoke(Arg<Action>.Is.Anything))
        .Do((Action<Action>)(action => action()));
    

    Hope that helps.