【问题标题】:Mocking local variables in C#在 C# 中模拟局部变量
【发布时间】:2014-01-31 11:48:18
【问题描述】:

我有一个方法,我要为其编写单元测试。方法的简化版:

public static bool IsUpdateAvailable()
{
    Version installedVersion = Util.GetInstalledVersionFromRegistry();
    Version availableVersion = Util.GetAvailableVersionFromRemote();

    bool isRemoteVersionNewer = IsVersionNewer(installedVersion, availableVersion);

    return isRemoteVersionNewer;
}

所以问题是让两个局部变量(installedVersion、availableVersion)不是从真实来源(在本例中来自注册表和互联网)而是从某种虚假来源读取它们的值。我无法修改上述方法。而且我试图了解如何通过使用例如 Moq 或 Microsoft Fakes 来模拟这两个变量。我确实在互联网上进行了搜索,但找不到一些相关的示例代码。 那么如何模拟上述方法的局部变量并测试该方法呢?

【问题讨论】:

  • Util.GetInstalledVersionFromRegistry() 是否位于与您正在测试的类不同的命名空间中?
  • @Jimmy 是的 Util.GetInstalledVersionFromRegistry() 在不同的命名空间中
  • 放弃我的要求,如果不更改一些代码就无法模拟它,请检查我的答案。
  • 我认为“模拟静态方法”可能是一个更合适的标题。

标签: c# .net unit-testing moq microsoft-fakes


【解决方案1】:

每个静态和硬编码的依赖项都存在同样的问题。 尽量避免静态,并首先将其归类为bad。 开发真正的论据来将某些东西标记为静态,而不是因为 R# 告诉过你。

如何解决这个问题是通过依赖注入。您必须通过参数注入依赖项以使其可测试。

ctor(Version installedVersion, Version availableVersion) {
    // Maybe store them in private fields.
}

public bool IsUpdateAvailable()
{
    bool isRemoteVersionNewer = IsVersionNewer(installedVersion, availableVersion);

    return isRemoteVersionNewer;
}

我想您现在明白了,您不必模拟变量本身。您可以使用不同的输入创建对象的不同实例。一种使用您的 Util. 方法构造对象,另一种使用您的单元测试的测试数据构造对象。

【讨论】:

    【解决方案2】:

    我也建议依赖注入,如果你能做到的话。如果你不能,要解决这个特殊问题,你可以使用垫片。

    http://msdn.microsoft.com/en-us/library/hh549176(v=vs.110).aspx#bkmk_static_methods

    您提到您不能对函数进行任何修改。我提议进行更改,但正如您将看到的那样,这并不重要。

    (代码未编译或测试)

    public static Version GetInstalledVersionFromRegistry()
    {
        return Util.GetInstalledVersionFromRegistry();
    }
    
    public static Version GetVersionFromRemote()
    {
        return Util.GetAvailableVersionFromRemote();
    }
    
    public static bool IsUpdateAvailable()
    {
        Version installedVersion = GetInstalledVersionFromRegistry();
        Version availableVersion = GetVersionFromRemote();
    
        bool isRemoteVersionNewer = IsVersionNewer(installedVersion, availableVersion);
    
        return isRemoteVersionNewer;
    }
    

    使用垫片测试

    using (ShimsContext.Create())
     {
            ShimYourclass.GetInstalledVersionFromRegistry=()=>new Version();
            ShimYourclass.GetInstalledVersionFromRegistry=()=>new Version();
    
            //test your class here    
            Yourclass.IsUpdateAvailable();
     }
    

    【讨论】:

      【解决方案3】:

      一般来说,任何静态的东西都不会是可模拟的,有一些框架可以做到这一点,但你可以很容易地在这条路线上制造出一团糟。

      在您的特殊情况下,如果这些参数在您的应用程序中真正全局适用,您可能需要AmbientContext。这将允许从静态容器随处访问它们,但仍允许模拟测试。

      尽管正如 TimmKrause 所说,在大多数情况下传递这些参数通常会更好。

      【讨论】:

        猜你喜欢
        • 2012-12-15
        • 1970-01-01
        • 2021-11-19
        • 2010-10-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多