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

StackOverflow https://stackoverflow.com/questions/19580880

  •  01-07-2022
  •  | 
  •  

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());
    }
}
有帮助吗?

解决方案

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.

其他提示

For the error message:

Rhino Mocks is telling you Expected #1, Actual #0. So it expects AddWindow to be invoked once but it isn't being invoked at all.

The one expectation that you have setup is:

osgController.Expect(x => x.AddWindow(osgViewModel.WindowProperties));

As for what the issue is:

Your method is being invoked in a Dispatcher. This thread isn't running in the test framework so you'll have to create one to run the test in.

You can see DispatcherTimer doesn't work in Console for an example of how to set this up.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top