NSubstitute icon indicating copy to clipboard operation
NSubstitute copied to clipboard

When..Do - versatile way of configuring substitutes using delegates

Open lukaszksoll opened this issue 1 year ago • 0 comments

Hi! I'm trying to create some helper methods to make working with NSubstitute more and more convenient. There is a case, when I need to check how many or which mocks have been already created.

Let's take the following case. I have a factory that creates some type of objects.

// Implementation
public class Factory : IFactory
{
  public IComponent Create(IParameter param)
  {
    return something();
  }
}

I want to have the ability to check all of the mocks created by that factory for specified action. In order to do so, I decided to use When.. Do methods:

public static ObservableCollection<TResultObject> SetupNewSubstitute<TSubstitute, TResultObject>(this TSubstitute substitute, Action<TSubstitute> when)
  where TSubstitute : class
  where TResultObject : class
{
  var createdMocks = new ObservableCollection<TResultObject>();

  substitute
    .WhenForAnyArgs(when)
    .Do(call =>
    {
      var mock = Substitute.For<TResultObject>();
      createdMocks.Add(mock);
    });

  return createdMocks;
}

But... it does not work at all. It does not invoke Do method at all for the following case. I've already created two overloads, one for Action and another one for Func.

Test implementation:

var mockFactory = Substitute.For<IFactory>();
var createdMocks = mockFactory.SetupNewSubstitute(f => f.Create(Arg.Any<IParameter>());

// Invoking action
// createdMocks is always empty.

Previously I used to use the following pattern:

var mockList = new List<IComponent>();
mockFactory.Create(Arg.Any<IParameter>()).Returns(i =>
{
  var mockResult = Substitute.For<IComponent>();
  mockList.Add(mockResult);
  return mockResult;
})));

I've also noticed that passing any substitute/real object to var createdMocks = mockFactory.SetupNewSubstitute(f => f.Create(ANY_REAL_OBJECT_OR_SUBSTITUTE); works.

But well... it's a boilerplate for us, and we'd like to get rid of it if possible.

Are you aware of any way that it could be solved?

lukaszksoll avatar Jul 26 '24 16:07 lukaszksoll