我正在使用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 {} };
但是我不断遇到同样的异常。我究竟做错了什么?
答案 0 :(得分:1)
WithOAuthBearerToken
是扩展方法,这意味着NSubstitute无法直接对其进行模拟。在扩展方法上调用text
或When..Do
时,它将运行扩展方法的实际代码。 (我建议将NSubstitute.Analyzers添加到测试项目中以检测这些情况。)
在撰写本文时,通过扩展方法实现,应该有可能模拟Returns
属性以引发所需的异常,但是我认为这会拖累过多的库内部知识,并且会导致脆性测试与该特定实现紧密结合(这是我们旨在通过模拟避免的事情!)。
如我在this answer中概述的那样,我会非常谨慎地以这种方式模拟第三方库:
另一个选择是在不同级别进行测试。我认为测试当前代码的摩擦在于,我们试图替代[第三方库]的详细信息,而不是为分区应用程序的逻辑详细信息而创建的接口。搜索“不要嘲笑您不拥有的类型”,以获取更多有关这可能导致问题的原因的信息(我在here之前就已经对此进行过介绍)。
如果可能的话,我建议尝试改用Flurl's built-in testing support。这样一来,您就可以伪装所需的行为,而无需有关Flurl内部实现的特定详细信息。