使用最小起订量模拟静态属性

Posted

技术标签:

【中文标题】使用最小起订量模拟静态属性【英文标题】:Mock static property with moq 【发布时间】:2011-01-25 20:37:34 【问题描述】:

我对使用moq 还是很陌生。我正在为HttpModule 创建一些单元测试用例,一切正常,直到我点击static 属性,如下所示

this.applicationPath = (HttpRuntime.AppDomainAppVirtualPath.Length > 1) ? HttpRuntime.AppDomainAppVirtualPath : String.Empty;

我不知道如何为static 类和属性创建模拟,例如HttpRuntime.AppDomainAppVirtualPathcontextrequestresponse 已经用我从 moq 获得的示例代码很好地模拟了。如果有人可以帮助我,我将不胜感激。

【问题讨论】:

【参考方案1】:

Moq 不能伪造静态成员。

作为一种解决方案,您可以创建一个包含静态属性的包装类(适配器模式)并伪造其成员。 例如:

public class HttpRuntimeWrapper

    public virtual string AppDomainAppVirtualPath 
     
        get
         
            return HttpRuntime.AppDomainAppVirtualPath; 
        
    

在生产代码中,您可以访问此类而不是 HttpRuntime 并伪造此属性:

[Test]
public void AppDomainAppVirtualPathTest()

    var mock = new Moq.Mock<HttpRuntimeWrapper>();
    mock.Setup(fake => fake.AppDomainAppVirtualPath).Returns("FakedPath");

    Assert.AreEqual("FakedPath", mock.Object.AppDomainAppVirtualPath);

另一个解决方案是使用隔离框架(如Typemock Isolator),您可以在其中伪造静态类和成员。 例如:

Isolate.WhenCalled(() => HttpRuntime.AppDomainAppVirtualPath)
       .WillReturn("FakedPath");

免责声明 - 我在 Typemock 工作

【讨论】:

在询问起订量时,建议商业产品有点过时。 为什么?这是一个选择。包装静态更好,但知道你的选择总是一件好事。 他正在寻求有关如何使用 Moq 执行此操作的解决方案。这就是为什么。 不,它似乎没有被替换为 HttpRuntime.AppDomainAppVirtualPath。测试在此调用时崩溃。有输入吗? +1 在 TypeMock 工作并参与社区活动 :)【参考方案2】:

Moq 不能使用 Moq 静态方法。

这在现实中并不是一件坏事,静态方法和类确实有它们的位置,但是对于逻辑它们使单元测试变得困难。在使用其他库时自然会遇到它们。为了解决这个问题,您需要在静态代码周围编写一个adapter(包装器),并提供一个接口。例如:

// Your static class - hard to mock
class StaticClass

   public static int ReturnOne() 
   
       return 1;
   


// Interface that you'll use for a wrapper
interface IStatic

    int ReturnOne();

注意,我省略了使用 IStatic 作为生产代码的具体类。全部 这将是一个使用 IStatic 的类,您的生产代码将使用该类,而不是上面的 StaticClass

然后是起订量:

var staticMock = new Mock<IStatic>();
staticMock.Setup(s => s.ReturnOne()).Returns(2);

【讨论】:

@Yasser 你破坏了代码示例,我正在恢复你的更改。【参考方案3】:

如前面的答案所述,您不能在静态方法上使用 MoQ,如果需要,最好的办法是围绕静态类创建一个包装器。

不过,我最近发现了Moles project。从主页; “Moles 允许用委托替换任何 .NET 方法。Moles 支持静态或非虚拟方法。”它可能对您当前的情况有用。

【讨论】:

有趣,会去看看。 不要使用鼹鼠。首先,它增加了很多麻烦并显着减慢了构建时间。其次,由于这条评论最初是由微软更新的模拟框架发布的,因此它已被取代。第三,它与 VS2012(使用较新的框架)不兼容,这在工作中很头疼,因为我们这里有很多用 Moles 编写的测试,需要在升级之前去 Molesified。模拟静态方法很诱人(尤其是遗留代码),但如果可以的话,IMO 最好只编写代码以对单元测试更友好。 当然可以,但是问题涉及我们大多数人无法修改的 HttpRuntime 类,在这种情况下,不可避免地需要以某种方式模拟静态方法/属性。【参考方案4】:

到目前为止,我发现的最佳解决方案是 Telerik 的 JustMock - 不幸的是,只有付费版本才允许模拟静态。

虽然包装静态的想法是一个很好的想法 - 你不能总是这样做。如果您想测试一些已经使用了一些静态类的代码,那么并不总是可以切换并使用包装器。在这种情况下,JustMock 看起来是一个合理的解决方案,我可能会在不久的将来将它用于一些解决方案。

【讨论】:

【参考方案5】:

您可以为此使用 Microsoft Fakes。它肯定会解决问题。 参考https://msdn.microsoft.com/en-us/library/hh549175.aspx

【讨论】:

虽然此链接可能会回答问题,但最好也在问题中说明重要细节(链接可能会失效)。【参考方案6】:

按照@Sujith 的建议使用Microsoft Fakes 是一个可行的解决方案。以下是你的实际操作方式:

在您的测试项目参考中找到System.Web并右键单击 选择“添加”。这增加了参考System.Web.4.0.0.0.Fakes

使用以下代码:

使用 (Microsoft.QualityTools.Testing.Fakes.ShimsContext.Create()) System.Web.Fakes.ShimHttpRuntime.AppDomainAppVirtualPathGet = () => "/"; // 做任何需要伪造的 AppDomainAppVirtualPath 的事情

【讨论】:

以上是关于使用最小起订量模拟静态属性的主要内容,如果未能解决你的问题,请参考以下文章

如何最小起订量委托回调和 lambda 方法

最小起订量中的设置序列

如何为起订量中的属性赋值?

使用最小起订量测试 Polly 重试策略

起订量,严格与宽松的使用

带参数的起订量 ReturnsAsync()