【问题标题】:Unit Testing nested methods单元测试嵌套方法
【发布时间】:2020-03-03 18:39:07
【问题描述】:

虽然我知道在对方法进行单元测试时,模拟它的所有依赖项非常重要,但我仍然对嵌套方法时会发生什么感到困惑?我是只模拟父方法的依赖关系,还是模拟子方法的依赖关系,还是对依赖对象的调用设置期望并设置确切的返回值,以便我可以执行测试我想要的?

例如,在下面的例子中,如果我们想对方法 B 进行单元测试,我们是只模拟 IHttpClientFactoryILogger 还是我们也将方法的返回值设置为我们实际期望的值,否则当测试方法执行它继续并尝试在它失败的地方执行methodC,因为var client = _clientFactory.CreateClient()行执行后client的值为null?

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 ..;
   }

}

【问题讨论】:

  • 它被称为单元测试,因为您测试单个单元 - 您可以在代码中找到的最小公共部分:f.i.一个类的方法。如果这个方法调用另一个方法(当然是同一个类,否则它会是一个你已经模拟的依赖项)那么你不应该关心,因为你也会为另一个方法编写一些单元测试:o)
  • 另一方面,如果 methodB 会调用一些受保护的或私有的方法(同一个类),你会关心 - 从调用者的角度来看?不,您会期望该方法将按照记录的方式工作,并且您不会关心实现细节。这正是您使用单元测试测试的内容:该单元的行为是否符合记录
  • 你只需要模拟你实际调用的方法,你不需要存根整个类。是的,您将模拟响应是您对测试用例的期望。无论测试中的特定单元需要什么来完成测试,mock 中的其他东西都不重要。

标签: c# unit-testing mocking moq


【解决方案1】:

所以你有一个 HTTP 客户端,一个获取一些结构化数据的高级方法和一个获取响应内容的低级方法。

这些东西更像是一门艺术,而不是硬性规则,但我最喜欢的规则是编写代码,可以将其所有 I/O 抽象化,然后模拟或测试实现 I/O 本身。这样大部分业务逻辑都可以测试。

I/O 可以是很多东西 - 文件、网络、用户输入,甚至可以是从证书存储中获取证书或读取注册表设置之类的东西。无论采用何种方法,在运行时从进程外部产生的任何数据都是 I/O。

当您模拟功能时,您最感兴趣的事情是验证方法的输入或模拟其输出(或两者兼而有之)。所以在你的模拟中,你不应该太关心实际的实现,因为你没有测试你的模拟方法——你正在测试调用它的任何东西。

那么...关于您的示例代码。如果您要测试 MethodB,则需要 MethodC 进行测试实现 - 通过模拟它所依赖的 HttpClient 或将其设置为 virtual 并在测试中覆盖它。

旁注:重用 HttpClient,与类保持一致

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-12-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-08-13
  • 2010-09-24
  • 1970-01-01
相关资源
最近更新 更多