简体   繁体   中英

Mocking Action<T> with NSubstitute

A proxy for a webservice needs unit testing without - obviously - hitting the web service.

This is the method I'd like to neuter -

public void Invoke(Action<T> action)
{
    Task.Run(async ()=> { await _invoker.Invoke(this, action); }).Wait();
}

Is there any way to mock the Action parameter using NSubstitute? I've been working along the lines of using

_proxy.When(x => x.Invoke($args_go_here)).Do(x => _counter++);

but I'm having real troubles formulating the Args expressions. If I could simply create a mock with the Action signature and pass it in, life would be much simpler and more readable.

As David recomments (see comments on question), I'm posting what actually solved my issue here.

The problem was testing that the code to call WCF services was actually running, sending the right stuff, etc. I would VERY STRONGLY recommend that anyone going down this route do so in TDD style as retrofitting unit tests over somebody else's working code is not an enjoyable experience.

In this case, proxies were not autogenerated but inherited from a single ProxyBase class which exposed the Invoke(Action action) method referenced above.

public void Invoke(Action<T> action)
{
    Task.Run(async ()=> { await _invoker.Invoke(this, action); }).Wait();
}

My first thought was to mock Action (and I did end up doing so) but this produced Service Not Found errors, quite correctly.

Eventually I ended up with an NSubstitute Automock of the (specific) Proxy Invoker class, created by actually passing dependencies into the constructor like so -

var myProxyMock = Substitute.For<MyProxy>(dependency1, dependency2);

and changing the base invoke method to a Virtual so that the substitute could override it, like so -

public virtual void Invoke(Action<T> action)
{
    Task.Run(async ()=> { await _invoker.Invoke(this, action); }).Wait();
}

Now, by substituting Action, I could actually test the surrounding code efficiently.

var actionSubstitute = Substitute.For<Action<MyService>>();

and apply relevant return values, natch.

so eventuially, we have -

myProxyMock.When(x => x.Invoke(Arg.Any<Action<MyService>>).Do(x => _counter++);

Problem solved. Many thanks, David.

If you just want a spy without making an external tracking variable, (what _counter is in Rich Bryant's great answer), it's possible to use ReceivedCalls() on the substitute. Below example uses System.Linq :

var myAction = Substitute.For<Action<string>>();
myAction.Invoke("abc");

// assert the Action<string> was called once
Assert.Equal(1, myAction.ReceivedCalls().Count());

// assert that the first parameter on the first call was "abc"
Assert.Equal("abc", myAction.ReceivedCalls().First().GetArguments().First());

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM