Reputation: 46366
I have an interface which can't be modified and has a ridiculous amount of methods (basically overloads--each is slightly different).
In some scenarios every method on the interface should throw the same exception. There are several of these scenarios, each with their own exception (stuff like SystemInMaintenanceModeException
, ClientRateLimitedException
, TheJanitorUnpluggedTheServerException
).
There are unit tests and the amount of setup for these exception-throwing scenarios feels downright silly... something like:
_mockedService.Setup(mock => mock.DoA(It.IsAny<string>()).Throws(expectedException);
_mockedService.Setup(mock => mock.DoB(It.IsAny<string>()).Throws(expectedException);
_mockedService.Setup(mock => mock.DoC(It.IsAny<string>()).Throws(expectedException);
...
_mockedService.Setup(mock => mock.DoX(It.IsAny<string>()).Throws(expectedException);
_mockedService.Setup(mock => mock.DoY(It.IsAny<string>()).Throws(expectedException);
_mockedService.Setup(mock => mock.DoZ(It.IsAny<string>()).Throws(expectedException);
Can Moq be configured to throw a specified exception for every method on the mocked interface?
PS: I'm aware that the Strict behavior will throw an exception on any call, but I need it to be specified exception(s).
Upvotes: 4
Views: 884
Reputation: 3193
There isn't an easy way to do this in Moq that I know of. Built in support would be via DefaultValueProvider
, but that'll only work for methods that return a value.
public class DefaultException : DefaultValueProvider
{
protected override object GetDefaultValue(Type type, Mock mock)
{
throw new InvalidOperationException("asdf");
}
}
...
var fooMock = new Mock<IFoo>();
fooMock.DefaultValueProvider = new DefaultException();
var foo = fooMock.Object;
Invoking(() => foo.Bar()).Should().Throw<InvalidOperationException>("asdf");
I've used IInterceptor
as mentioned in a another answer here and it'll work as described. My usage was over the Mock<T>
itself so required a bit more care, but over the target interface directly should present nothing unusual.
Holistically this feels like a problem that AutoMoq could solve, with some customisation around the method set up. I couldn't find a ready made solution but it'd be what I'd look into if I wanted a pure solution to the problem.
Upvotes: 1
Reputation: 25935
I would recommend using FakeItEasy, it has great support for this scenario:
A.CallTo(_service).Throws(expectedException)
This will make any method on the mock throw the specified exception.
Upvotes: 2
Reputation: 1583
Moq uses Castle DynamicProxy, so you could use it directly like this
using System;
using System.Threading.Tasks;
using Castle.DynamicProxy;
public class Interceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
throw new NotImplementedException();
}
}
public interface ITest
{
void Test1();
Task Test2(string a);
int Add(int a1, int a2);
}
class Program
{
static void Main(string[] args)
{
{
ProxyGenerator generator = new ProxyGenerator();
var c = generator.CreateInterfaceProxyWithoutTarget<ITest>(new Interceptor());
try
{
var r = c.Add(11, 22);
Console.WriteLine(r);
}
catch (NotImplementedException e)
{
}
c.Test2("");
Console.ReadKey();
}
Console.WriteLine("Hello World!");
}
}
Also check this question
For Task returning methods you would probably need extra logic like to return Task.FromException.
Upvotes: 2