mock可以配置为在任何方法调用上抛出指定的异常吗?



我有一个无法修改的接口,并且有大量的方法(基本上是重载——每个都略有不同)。

在某些情况下,接口上的每个方法都应该抛出相同的异常。有几个这样的场景,每个都有自己的例外(如SystemInMaintenanceModeException,ClientRateLimitedException,TheJanitorUnpluggedTheServerException)。

有单元测试和设置这些异常抛出场景的数量感觉非常愚蠢…比如:

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

可以配置Moq为模拟接口上的每个方法抛出指定的异常吗?

PS:我知道Strict行为会在任何调用中抛出异常,但我需要指定异常。

Moq使用Castle DynamicProxy,所以你可以像这样直接使用它

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!");
}
}

也检查这个问题

对于Task返回方法,您可能需要额外的逻辑,例如返回Task. fromexception。

我建议使用FakeItEasy,它对这种情况有很好的支持:

A.CallTo(_service).Throws(expectedException)

这将使mock上的任何方法抛出指定的异常。

https://fakeiteasy.readthedocs.io/en/stable/specifying-a-call-to-configure/specifying-a-call-to-any-method-or-property

据我所知,在Moq中没有一种简单的方法可以做到这一点。内置支持将通过DefaultValueProvider,但这只适用于返回值的方法。

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

我已经使用了IInterceptor,正如在这里的另一个答案中提到的,它会像描述的那样工作。我的用法是在Mock<T>本身之上,所以需要更多的注意,但是直接在目标接口之上应该没有什么不寻常的。

总的来说,这感觉像是AutoMoq可以解决的问题,在方法设置上进行一些定制。我找不到现成的解决方案,但如果我想要一个纯粹的解决方案,我就会去研究一下。

相关内容

最新更新