为使用RestClient的实用程序编写单元测试

时间:2018-10-17 07:47:16

标签: c# unit-testing restsharp

我们决定创建一个可以在多个项目中重复使用的HTTP记录器,我们创建了一个类似于以下的实用程序。

// pseudo-code
public class HttpLog{
      private readonly string uri;
      private readonly RestClient client;

      public HttpLog(string uri){
          this.uri = uri;
          // notice the initialization of rest client
          this.client = new RestClient();
      }

     void write(object data){
         this.client.uri = this.uri + endpoint;
         this.client.postAsync(data);
     }           
}

使用者应提供URI,并且我们已经公开了公共写入方法来记录数据,但是,由于它初始化了其余客户端,因此我们无法对HttpLog类进行单元测试。我们正在创建实用程序,因此没有使用依赖注入。

在如何重构或单元测试。write()方法方面,任何帮助将不胜感激。

我们可以想到两种方法

  • 构造函数重载(这不是仅用于单元测试的有效方法)
  • 将客户财产设为公开{get; set}也违反了OOP原则。

请告诉我们是否有更好的方法对该代码进行单元测试。

下面给出的答案是使用构造函数重载或将该属性设置为公开

为什么我不喜欢依赖注入或构造函数重载,因为我坚信消费者/客户不应该关心或担心实现细节。它们应尽可能地抽象。如果使它们处于构造函数重载中,那么您正在寻找一种污染抽象的方法。

例如,如果您使用RestClient或HttpClient,他们不要求您提供有关如何编写数据的HTTP实现,他们只是询问您URI和要发布的数据,这才是对最终用户的真正抽象。

如果我的假设错误,请纠正我

2 个答案:

答案 0 :(得分:1)

第一件事:要测试什么?您的方法,还是REST服务本身?

由于您说“我们无法对HttpLog类进行单元测试” ,因此我推断您正在尝试测试您的类。

因此,您应该在没有REST服务的情况下对其进行测试[em] (这是外部依赖项)。 REST客户端应作为依赖项注入,因此可以轻松对其进行模拟。

  

由于我们正在创建实用程序,因此我们不使用依赖项注入。

这不是跳过依赖项注入的有效参数。

注意:我从您的陈述中推断您知道如何实现依赖注入,您只是选择了不这样做。我将省略一个依赖注入的实际示例,因此该答案可以集中在核心问题上:您决定不使用依赖注入。

  
      
  1. 构造函数重载(这不是仅用于单元测试的有效方法)
  2.   

这破坏了测试的重点。您将为测试和(实际)运行时创建不同的代码路径,这意味着测试不再(完全)测试运行时代码执行。

当前,您的构造函数仅实例化其余客户端,因此您并没有太多妥协。但是,如果构造函数所做的不止于此,那将不适用。其次,如果要测试与运行时实际使用的构造函数不同的构造函数,则将无法检测到任何回归。

  
      
  1. 将客户财产设为公开{get; set}也违反了OOP原则。
  2.   

您的第二条建议直接证明您愿意(并尝试)注入依赖项。您只是试图通过可公开设置的属性(而不是构造函数参数)注入它。

您正确地认为,使用可公开设置的属性不是一个好决定,因为它为其他问题打开了大门。
相比之下,使用构造函数参数可以实现相同的功能(公开选择客户端),而不会损害封装(在对象的生存期内无法更改客户端)。

因此,答案是使用依赖项注入

答案 1 :(得分:1)

  

由于我们正在创建实用程序,因此我们不使用依赖项注入。

那不是原因。如果使用依赖项并希望能够对其进行正确测试,则应使用依赖项注入。这并不意味着您不能为普通用户提供默认的实现。

提供构造函数重载。我不知道你为什么认为这将是“低效的”。

示例:

public class HttpLog{
      private readonly string uri;
      private readonly RestClient client;

      public HttpLog(string uri) : this(uri, new RestClient()){
      }

      public HttpLog(string uri, RestClient restClient){
          this.uri = uri;
          // notice the initialization of rest client
          this.client = restClient;
      }

     void write(object data){
         this.client.uri = this.uri + endpoint;
         this.client.postAsync(data);
     }           
}