[英]Mocking IFlurl library methods using NSubstitute is throwing null reference exception
我正在使用flurl,并且尝试对以下代码进行单元测试:
public class MyRestClient
{
public async Task<T> Request<T>(IFlurlRequest flurlRequest)
{
try
{
return await flurlRequest
.WithOAuthBearerToken("my-hardcoded-token")
.GetAsync()
.ReceiveJson<T>();
}
catch(HttpFlurlException)
{
throw new MyCustomException();
}
}
}
我要测试的是,如果flurlRequest
抛出HttpFlurlException
类型的异常,则它将抛出MyCustomException
。 我的想法是发送flurlrequest
并引发异常。 这是我布置测试的方式:
var moq = Substitute.For<IFlurlRequest>();
// Problem is with line below:
moq.When(x => x.WithOAuthBearerToken("dummy")).Do(x => { throw new HttpFlurlException(); } );
var myClient = new MyRestClient();
Func<Task> call = async () => { await myClient.Request<object>(moq); };
// FluentAssertions
call.Should().Throw<MyCustomException>();
运行时的代码返回NullReferenceException:
Exception has occurred: CLR/System.NullReferenceException
An exception of type 'System.NullReferenceException' occurred in
Flurl.Http.dll but was not handled in user code: 'Object reference not
set to an instance of an object.'
at Flurl.Http.HeaderExtensions.WithHeader[T](T clientOrRequest, String name, Object value)
所以我看到了与标头有关的东西...所以我尝试通过添加以下方法来模拟它:
var moq = Substitute.For<IFlurlRequest>();
moq.Headers.Returns(new Dictionary<string, object> { {"dummy", new {} };
但我不断遇到同样的例外。 我究竟做错了什么?
WithOAuthBearerToken
是一个扩展方法,这意味着NSubstitute无法直接对其进行模拟。 当您在扩展方法上调用When..Do
或Returns
时,它将运行该扩展方法的实际代码。 (我建议将NSubstitute.Analyzers添加到测试项目中以检测这些情况。)
在编写本文时跟踪扩展方法的实现,应该可以模拟Headers
属性以引发所需的异常,但是我认为这会拖累过多的库内部知识,并且会导致脆弱的测试。与该特定实现紧密结合(这是我们旨在通过模拟避免的目标!)。
正如我在此答案中概述的那样,我将非常谨慎地以这种方式模拟第三方库:
另一个选择是在不同级别进行测试。 我认为测试当前代码的摩擦在于,我们试图替代[第三方库]的详细信息,而不是为分区应用程序的逻辑详细信息而创建的接口。 搜索“不,你没有自己的模拟类型”为什么这可能是一个问题的详细信息(我已经写它之前在这里 )。
如果可能,我建议尝试使用Flurl的内置测试支持 。 这应该使您能够伪造所需的行为,而无需有关Flurl内部实现的特定详细信息。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.