5

I have the following method signature in an interface:

public interface ISettingsUtil
{
    T GetConfig<T>(string setting, dynamic settings);
}

Which I have attempted to mock:

var settingsUtil = Substitute.For<ISettingsUtil>();
var maxImageSize = settingsUtil.GetConfig<long>("maxImageSize", 
                                              Arg.Any<dynamic>()).Returns(100L);

This throws a Microsoft.CSharp.RuntimeBinder.RuntimeBinderException exception on the 2nd line:

'long' does not contain a definition for 'Returns'

Any thoughts on how to mock T GetConfig<T>(string setting, dynamic settings) correctly?

Kapil Khandelwal
  • 15,958
  • 2
  • 45
  • 52
Anders
  • 15,227
  • 5
  • 32
  • 42

2 Answers2

5

For anyone still struggling with this, you can actually mock dynamics in NSubsitute, it just requires jumping through some minor hoops. See the below case of mocking out calls to a signalR client hub.

The important line is this one:

SubstituteExtensions.Returns(_hubContext.Clients.All, _mockClient);

In order to mock the dynamic I have created an interface with the methods I want to listen for. You then need to use SubstituteExtensions.Returns rather than simply chaining a .Returns at the end of the object.
If you don't need to verify anything you could also use an anonymous object.

Full code sample follows:

[TestFixture]
public class FooHubFixture
{
    private IConnectionManager _connectionManager;
    private IHubContext _hubContext;
    private IMockClient _mockClient;

    [SetUp]
    public void SetUp()
    {
        _hubContext = Substitute.For<IHubContext>();
        _connectionManager = Substitute.For<IConnectionManager>();

        _connectionManager.GetHubContext<FooHub>().Returns(_hubContext);
        _mockClient = Substitute.For<IMockClient>();
        SubstituteExtensions.Returns(_hubContext.Clients.All, _mockClient);
    }

    [Test]
    public void PushFooUpdateToHub_CallsUpdateFooOnHubClients()
    {
        var fooDto = new FooDto();
        var hub = new FooHub(_connectionManager);
        hub.PushFooUpdateToHub(fooDto);
        _mockClient.Received().updateFoo(fooDto);
    }

    public interface IMockClient
    {
        void updateFoo(object val);
    }
}



public class FooHub : Hub
    {
        private readonly IConnectionManager _connectionManager;

        public FooHub(IConnectionManager connectionManager)
        {
            _connectionManager = connectionManager;
        }

        public void PushFooUpdateToHub(FooDto fooDto)
        {
            var context = _connectionManager.GetHubContext<FooHub>();
            context.Clients.All.updateFoo(fooDto);
        }
    }
  • 1
    Thank you Brett, this was my exact problem, I think I love you! :) – Andriy Volkov Feb 18 '14 at 17:38
  • Any idea how one would go about using the static `Returns` method to stub a method returning a dynamic type rather than a property? – Ryan Norbauer Mar 11 '14 at 21:14
  • This doesn't seem to work anymore. When I use: `SubstituteExtensions.Returns(_hubContext.Clients.All, _mockClient);` at runtime I get an error saying it can't tell whether I'm calling the version that takes an ObjectProxy or a Task as the first argument. – jfren484 Aug 17 '16 at 03:54
3

NSubstitute does not work with members that use dynamic. (Github issue)

David Tchepak
  • 9,826
  • 2
  • 56
  • 68
  • Too bad, NSubstitute was rapidly becoming my favorite - hopefully the issue is resolved soon! – Anders Nov 02 '12 at 14:15