Search code examples
c#unit-testingdelegatesnunitrhino-mocks

Rhino Mocks Stub not calling .WhenCalled action


I'm writing unit tests using NUnit and Rhino Mocks to generate a stub. I'd like to use the .WhenCalled method to control the return value of a stubbed method. It works as expected when I pass a lambda statement to the method, but not when I pass a method delegate.

For example, say I have the following interface:

public interface INumberCollection
{
  int[] GetNumbers();
}

And for my test class I have the following:

[TestFixture]
public class MyTests
{
  private INumberCollection _collection;
  private Action<MethodInvocation> _action;

  [OneTimeSetUp]
  public void MyTests_OneTimeSetup()
  {
    _collection = MockRepository.GenerateStub<INumberCollection>();
    _collection.Stub(c => c.GetNumbers())
      .Repeat.Any()
      .Return(new[] {0, 0, 0})
      .WhenCalled(x => { x.ReturnValue = new[] {1, 2, 3}; });
  }

  [Test]
  public void MyTest()
  {
    var result = _collection.GetNumbers();

    Assert.That(result, Is.EqualTo(new[] {1, 2, 3}));
  }
}

The test passes. However, the test fails when I replace the setup method with the following:

[OneTimeSetUp]
public void MyTests_OneTimeSetup()
{
  _collection = MockRepository.GenerateStub<INumberCollection>();
  _collection.Stub(c => c.GetNumbers())
    .Repeat.Any()
    .Return(new[] {0, 0, 0})
    .WhenCalled(_action);

  _action = x => { x.ReturnValue = new[] { 1, 2, 3 }; };
}

I expected .WhenCalled to call the delegate stored in _action and return {1, 2, 3}, but instead it's returning {0, 0, 0}, as if .WhenCalled is being skipped completely. I even inserted a breakpoint inside the lambda and verified that it is never hit when debugging the test.

Why is _action never getting called?


Solution

  • _action isn't getting called because it is null when it is passed to .WhenCalled.

    Because _action is being passed to .WhenCalled as a parameter, changing its value after it's been passed doesn't have any effect. To fix this, make the assignment before passing it to .WhenCalled:

    [OneTimeSetUp]
    public void MyTests_OneTimeSetup()
    {
      _action = x => { x.ReturnValue = new[] { 1, 2, 3 }; };
    
      _collection = MockRepository.GenerateStub<INumberCollection>();
      _collection.Stub(c => c.GetNumbers())
        .Repeat.Any()
        .Return(new[] {0, 0, 0})
        .WhenCalled(_action);
    }