简体   繁体   English

在 Nuget Package 中抽象/连接 class 以进行单元测试

[英]Abstracting/Interfacing a class within a Nuget Package for Unit Testing

So I have a Application that currrently uses the EAGetMail nuget package for scraping EmailServers.所以我有一个当前使用 EAGetMail nuget package 来抓取电子邮件服务器的应用程序。 I am attempting to refactor my project and interface individual pieces for mocking in Unit Tests.我正在尝试重构我的项目并在单元测试中为 mocking 连接各个部分。 My current issue is the classes in the package don't seem to be interfaced and I am not sure if interfacing them indirectly would work.我当前的问题是 package 中的类似乎没有接口,我不确定间接接口是否可行。 Could just be a lack of understanding or a different way t enter image description here o mock the data is needed.可能只是缺乏理解或以不同的方式在此处输入图像描述或模拟需要数据。 Anything would help!任何事情都会有所帮助!

enter image description here在此处输入图像描述

在此处输入图像描述

As the classes are also sealed, there are no options to create mocks directly.由于类也是密封的,因此没有直接创建模拟的选项。 If you are refactoring your codebase anyway, your best option would be to put all the email related stuff in wrapper classes and create an interface for these wrappers.如果你无论如何都要重构你的代码库,你最好的选择是将所有 email 相关的东西放在包装器类中并为这些包装器创建一个接口。

Mocking those interfaces is easy, plus you have the code that depends on the component assembled in one place. Mocking 这些接口很简单,而且您拥有依赖于组装在一个地方的组件的代码。 If you decide to move on to another package later on, your changes are better that you only need to change the wrapper classes and not several spots in your codebase.如果您稍后决定继续使用另一个 package,您的更改会更好,因为您只需要更改包装类而不是代码库中的几个位置。

As regards unit testing the wrapper classes, those should be as thin as possible.关于包装类的单元测试,它们应该尽可能薄。 The package publisher should unit test its components, so there would not be anything left to test in the wrappers. package 发布者应该对它的组件进行单元测试,这样包装器中就没有任何要测试的东西了。


As regards the example method Login , the method comprises three blocks:关于示例方法Login ,该方法包括三个块:

  1. The code that determines the host server.确定主机服务器的代码。 This is your code that you need to test.这是您需要测试的代码。 However, testing this code is easy, because there are no dependencies to the package.但是,测试此代码很容易,因为它不依赖于 package。
  2. The setup code for the MailServer class. This code uses code from the package and creates the MailServer . MailServer class 的设置代码。此代码使用 package 中的代码并创建MailServer You could test whether the settings are correct.您可以测试设置是否正确。 You would not have to mock anything here, because AFAIK MailServer should be more or less like a DTO.你不必在这里模拟任何东西,因为 AFAIK MailServer应该或多或少像一个 DTO。 So you could test whether your code sets the correct options.因此您可以测试您的代码是否设置了正确的选项。
  3. The code that connects to the mail server.连接到邮件服务器的代码。 This code uses the methods of the package. If the publisher tests its code thorougly then testing it again would not be too valuable.此代码使用 package 的方法。如果发布者彻底测试其代码,那么再次测试它的价值就不会太大。

To provide some code, a rough outline could be the following:为了提供一些代码,粗略的大纲如下:

public class HostNameProvider
{
  public virtual string GetHostNameFromMailAddress(string mailAddress)
  {
    // Here goes the Substring and Switch
    // You can create unit tests that check 
    // whether the output of the method meets your expectations
  }
}

public class MailServerBuilder
{
   public virtual MailServer Build(string userName, ...)
   {
     // This helper class is used by your wrapper for the library
     // You can create a test for the method and check the 
     // MailServer object
   }
}

public interface IMailClientWrapper 
{
  void Connect(string userName, ...);
}

public class MailClientWrapper : IMailClientWrapper
{
  private readonly MailServerBuilder _bldr;
  
  public MailClientWrapper(MailServerBuilder bldr)
  {
    _bldr = bldr;
  }

  public void Connect(string userName, ...)
  {
     var server = _bldr.Build(userName, ...);
     // Connect to the server
     // There would be no unit tests for this code 
     // as it relies on sealed classes
  }
}

public class LoginService  // or how your class is named 
{
  private readonly HostNameProvider _hostNameProv;
  private readonly IMailClientWrapper _mailClient;
  
  public LoginService(
    HostNameProvider hostNameProv, 
    IMailClientWrapper mailClient)
  {
    _hostNameProv = hostNameProv;
    _mailClient = mailClient;
  }

  public bool Login()
  {
    var hostName = _hostNameProv.GetHostNameFromMailAddress(mailAddress);
    try
    {
      _mailClient.Connect(userName, ...);
    }
    catch 
    {
      return false;
    }
    return true;
  }
}

Above sample splits the code into several blocks;上面的示例将代码分成几个块; most of them can be tested.其中大部分都可以测试。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM