【问题标题】:abstracting an interface to a class that has extension methods将接口抽象为具有扩展方法的类
【发布时间】:2016-12-30 10:16:37
【问题描述】:

如果我在该类中使用扩展方法,如何将具体类替换为其接口以进行单元测试?

我有一个方法:

[HttpGet]
[Route("/yoyo/{yoyoId:int}/accounts")]
public ResponseYoyoEnvelope GetAccountsByYoyoId([FromBody] RequestYoyoEnvelope requestYoyoEnvelope, int yoyoId)
{
    var responseYoyoEnvelope = requestYoyoEnvelope.ToResponseYoyoEnvelope();

    // get our list of accounts
    // responseEnvelope.Data = //list of accounts
    return responseYoyoEnvelope;
}

我想更换:

RequestYoyoEnvelope requestYoyoEnvelope

带有抽象:

IRequestYoyoEnvelope requestYoyoEnvelope

但是,ToResponseYoyoEnvelope 是一种扩展方法。

如果我在该类中使用扩展方法,如何将具体类替换为其接口以进行单元测试?

【问题讨论】:

    标签: c# visual-studio unit-testing nunit


    【解决方案1】:

    您可以针对接口而不是具体类编写扩展方法:

    public static class Class2
    {
        public static void Extension(this ITestInterface test)
        {
            Console.Out.WriteLine("This is allowed");
        }
    }
    

    那么你可以这样做:

    // "Test" is some class that implements the ITestInterface interface
    ITestInterface useExtensionMethod = new Test();
    useExtensionMethod.Extension();
    

    还要注意,即使 useExtensionMethod 不是明确的 ITestInterface 类型,这仍然有效:

    Test useExtensionMethod = new Test();
    useExtensionMethod.Extension();
    

    controversy 关于这是否代表装饰器模式,但至少请记住,扩展方法实际上并不是接口本身的一部分 - it's still a static method“在幕后”,只是编译器的让您可以方便地将其视为实例方法。

    【讨论】:

      【解决方案2】:

      假设

      public class RequestYoyoEnvelope : IRequestYoyoEnvelope { ... }
      

      您的扩展方法需要以接口为目标

      public static ResponseYoyoEnvelope ToResponseYoyoEnvelope(this IRequestYoyoEnvelope target) { ... }
      

      保持操作不变,因为模型绑定器在绑定接口时会遇到问题。

      在您的单元测试中,您通过了RequestYoyoEnvelope 的具体实现,并且应该能够测试更新后的扩展方法。

      从您的示例中,您不需要接口来测试该方法是否是被测方法。只需新建一个模型实例并在单元测试期间将其传递给方法。

      [TestMethod]
      public void GetAccountsByYoyoIdTest() {
          //Arrange
          var controller = new YoyoController();
          var yoyoId = 123456;
          var model = new RequestYoyoEnvelope {
              //you populate properties for test
          };
          //Act
          var result = controller.GetAccountsByYoyoId(model, yoyoId);
      
          //Assert
          //...do your assertions.
      }
      

      【讨论】:

      • 一旦我意识到我错过了什么,我就调整了答案——这是一个 API 端点。然后我读了这个答案 - @Nkosi 没有错过它,而且这个答案更准确。
      猜你喜欢
      • 2012-09-22
      • 2013-05-20
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-12-12
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多