Mocking Action<T> with NSubstitute

我的梦境 提交于 2019-12-12 10:10:08

问题


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.


回答1:


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.




回答2:


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());


来源:https://stackoverflow.com/questions/29300512/mocking-actiont-with-nsubstitute

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!