【问题标题】:NSubstitute Mock static class and static methodNSubstitute Mock 静态类和静态方法
【发布时间】:2019-10-29 07:18:47
【问题描述】:

我是单元测试的新手,我正在尝试在静态类中模拟静态方法。我已经读到你不能这样做,但我正在寻找一种解决方法。

我无法修改代码,并且在不使用静态的情况下制作相同的函数不是一个选项,因为他们会检查测试的代码覆盖率,我需要至少 90%。
我已经尝试模拟它使用的变量,但它不起作用。

public static class MyClass
{
    public static response MyMethod(HttpSessionStateBase Session, 
        otherVariable, stringVariable)
    {
        //some code
    }
}

public ActionResult MyClassTested()
{
    var response = MyClass.MyMethod(Session);
    //more code
}

我的问题是这个方法在一个控制器中,它声明一个带有响应的 var,并据此重定向用户。

【问题讨论】:

    标签: c# visual-studio-2017 mocking nsubstitute


    【解决方案1】:

    对于这类问题可能有更好的解决方案...取决于您可以解决的问题。

    我最近在编写了一个静态实用程序类后自己遇到了这个问题,该类基本上用于创建各种 Guid 格式的截断。在编写集成测试时,我意识到我需要控制从该实用程序类生成的随机 Id,以便我可以故意将此 Id 发布到 API,然后对结果进行断言。

    我当时采用的解决方案是提供静态类的实现,但从非静态类中调用该实现(包装静态方法调用),我可以在 DI 容器中注册和注入.这个非静态类将是主要的主力,但静态实现将在我需要从另一个静态方法调用这些方法的情况下可用(例如,我已经编写了很多集成设置代码作为 IWevApplicationFactory 的扩展,并使用静态实用程序创建数据库名称)。

    在代码中,例如

    // my static implementation - only use this within other static methods when necessary. Avoid as much as possible.
    public static class StaticGuidUtilities 
    {
        public static string CreateShortenedGuid([Range(1, 4)] int take)
        {
            var useNumParts = (take > 4) ? 4 : take;
            var ids = Guid.NewGuid().ToString().Split('-').Take(useNumParts).ToList();
            return string.Join('-', ids);
        }
    }
    
    
    // Register this abstraction in the DI container and use it as the default guid utility class
    public interface IGuidUtilities
    {
        string CreateShortenedGuid([Range(1, 4)] int take);
    }
    
    // Non-static implementation
    public class GuidUtitlities : IGuidUtilities
    {
        public string CreateShortenedGuid([Range(1, 4)] int take)
        {
            return StaticGuidUtilities.CreateShortenedGuid(take);
        }
    }
    
    ----
    
    // In the tests, I can use NSubstitute...
    // (Doesn't coding to the abstraction make our lives so much easier?)
    var guidUtility = Substitute.For<IGuidUtilities>();
    var myTestId = "test-123";
    guidUtility.CreateShortenedGuid(1).Returns(myTestId);
    
    // Execute code and assert on 'myTestId' 
    // This method will call the injected non-static utilty class and return the id
    var result = subjectUndertest.MethodUnderTest();
    
    // Shouldly syntax
    result.Id.ShouldBe(myTestId);
    

    【讨论】:

      【解决方案2】:

      如果您无法修改代码,那么我认为无法使用基于 DynamicProxy 的库(如 NSubstitute)来解决此问题。这些库使用inheritance to intercept members on classes,这对于静态和非虚拟成员是不可能的。

      我建议尝试Fakes。该页面上的一个示例涵盖了存根DateTime.Now

      可以模拟静态成员的其他替代方法包括 TypeMock 和 Telerik JustMock。

      相关问题:https://stackoverflow.com/q/5864076/906

      【讨论】:

      • 是的,我也读到了,但我使用的是专业版 VS 2017,所以我没有假货,但似乎我无法做到,我必须使用其他东西或修改代码
      • @RicardoSanchezSantos 你可以试试 TypeMock 或 Telerik JustMock。我已经更新了提到这些的答案。如here 所述,大多数 .NET 模拟库通过继承拦截对类的调用,因此您需要选择通过分析 API 或类似方式工作的其他库之一。
      • 有没有类似 typemock 或 telerik free 的东西?
      • 我尝试安装 Pose,但我的框架有问题 = 4.6.2 与 Pose 不兼容,我也尝试过 Smock,但我不太确定如何使用它,我正在调查微软的痣
      • 抱歉,我不确定定价。最好在他们的项目站点上询问 Pose 和 Smock 以及关于您遇到的特定问题的其他 SO 问题。祝你好运!
      猜你喜欢
      • 1970-01-01
      • 2011-01-17
      • 1970-01-01
      • 2011-07-11
      • 2021-08-11
      • 2020-12-27
      • 2016-01-26
      • 2013-07-21
      • 2016-07-29
      相关资源
      最近更新 更多