使用moq模拟静态属性

时间:2010-03-10 11:17:30

标签: c# asp.net unit-testing moq

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

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

我不知道如何为static类和HttpRuntime.AppDomainAppVirtualPath之类的属性创建模拟。我从moq获得的示例代码已经模拟了contextrequestresponse。如果有人能帮助我,我将不胜感激。

6 个答案:

答案 0 :(得分:60)

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工作

答案 1 :(得分:11)

你不能使用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

然后用Moq:

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

答案 2 :(得分:3)

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

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

答案 3 :(得分:2)

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

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

答案 4 :(得分:1)

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

答案 5 :(得分:0)

使用@Sujith建议的Microsoft Fakes是可行的解决方案。这是您实际的操作方式:

  • 在您对测试项目的引用中找到System.Web,然后右键单击
  • 选择“添加”。这会添加参考System.Web.4.0.0.0.Fakes
  • 使用以下代码:

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