C# 单元测试嵌套方法
虽然我理解在单元测试一个方法时,模拟它的所有依赖项是非常重要的,但我仍然不清楚的是,当该方法被嵌套时会发生什么?我是只模拟父方法的依赖关系,还是也模拟子方法的依赖关系,还是设置对依赖对象的调用的期望值,并设置准确的返回值,以便执行所需的测试 例如,在下面的例子中,如果我们想对方法B进行单元测试,我们是否只模拟C# 单元测试嵌套方法,c#,unit-testing,mocking,moq,C#,Unit Testing,Mocking,Moq,虽然我理解在单元测试一个方法时,模拟它的所有依赖项是非常重要的,但我仍然不清楚的是,当该方法被嵌套时会发生什么?我是只模拟父方法的依赖关系,还是也模拟子方法的依赖关系,还是设置对依赖对象的调用的期望值,并设置准确的返回值,以便执行所需的测试 例如,在下面的例子中,如果我们想对方法B进行单元测试,我们是否只模拟IHttpClientFactory&ILogger,或者我们是否也将方法的返回值设置为我们实际期望的值,因为否则,当测试方法执行时,它会继续执行,并尝试执行methodC,但失败的原因是c
IHttpClientFactory
&ILogger
,或者我们是否也将方法的返回值设置为我们实际期望的值,因为否则,当测试方法执行时,它会继续执行,并尝试执行methodC,但失败的原因是client
行var client=_clientFactory.CreateClient()是否为空
using System.Net.Http;
...
public class classA
{
private readonly IHttpClientFactory _clientFactory;
private sting url = "...";
private ILogger _log { get; set; }
...
public classA(ILogger log, IHttpClientFactory clientFactory, ...)
{
_log = log;
_clientFactory = clientFactory;
...
}
public string methodB(string inputB)
{
var varB = methodC(inputB);
...
return ..;
}
public string methodC(string inputC)
{
...
var client = _clientFactory.CreateClient();
client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
HttpResponseMessage httpResponseMessage = await client.PostAsync(url, new StringContent(inputC, Encoding.UTF8, "application/json"));
responJsonText = await httpResponseMessage.Content.ReadAsStringAsync();
...
return ..;
}
}
因此,您有一个HTTP客户端,一个获取结构化数据的高级方法和一个获取响应内容的低级方法
这些东西比硬规则更像是一门艺术,但我最喜欢的规则是编写代码,将所有I/O抽象出来,然后模拟或测试实现I/O本身。这样,大部分业务逻辑都是可测试的
I/O可以是很多东西—文件、网络、用户输入,甚至可以是从证书存储获取证书或读取注册表设置。在运行时从进程外部生成的任何数据都是I/O,无论采用何种方法
当您模拟功能时,您最感兴趣的事情是验证方法的输入或模拟其输出(或两者兼而有之)。所以在你的模拟中,你不应该太在意实际的实现,因为你不是在测试你的模拟方法——你在测试任何调用它的东西
所以。。。关于您的示例代码。如果您试图测试MethodB,您需要MethodC有一个测试实现——要么模拟它所依赖的HttpClient,要么使其虚拟化,并在测试中重写它
旁注:重用HttpClient,并将其与类保持在一起它被称为单元测试,因为您只测试一个单元—您可以在代码中找到的最小公共部分:f.i.类的方法。如果此方法调用另一个方法(当然是同一类的,否则它将是您已经模拟过的依赖项),那么您不应该关心,因为您也将为该另一个方法编写一些单元测试:o)另一方面,如果methodB调用(同一类的)某些受保护或私有方法从打电话的人的角度来看,你会在意吗?不,您希望该方法能够像文档中描述的那样工作,而不关心实现细节。这正是您使用单元测试测试的内容:单元的行为是否像文档一样?您只需要模拟您实际调用的方法,而不需要删除整个类。是的,您将模拟响应,使其成为您对测试用例的期望。无论被测试的具体单元需要完成测试,模拟中没有其他东西是重要的。下面是一个MS如何做到这一点的例子@SirRufo是一个很好的例子!这是抽象高级客户机的方法。如果OP正在编写该客户机,那么抽象将围绕HttpClient