Moq是静态类中的对象

时间:2017-02-09 04:10:16

标签: c# unit-testing nunit moq

我无法让Moq模拟在静态方法中创建的对象。 这是我的moq和代码

代码:

public interface IConfigHelper
{
    string GetConfiguration(string sectionName, string elementName);
}

public class ConfigHelper : IConfigHelper
{
    public ConfigHelper() { }

    public virtual string GetConfiguration(string sectionName, string elementName)
    {
        string retValue = String.Empty;
        //Does things to get configuration and return a value    
        return retValue;
    }
}

public class myRealClass
{
    public myRealClass(){}
    public string myworkingMethod()
    {
        var retValue = String.Empty;
        retValue = utilSvc.GetConfigurationValue();
        return retValue;
    }
}

public static class utilSvc
{
    public static string GetConfigurationValue()
    {
        ConfigHelper configUtil = new ConfigHelper(); //NOT BEING MOCKED
        return configUtil.GetConfiguration("sectionName/sectionElement", "ClinicalSystem");
    }
}

使用Moq进行测试

[TestFixture(TestName = "Tests")]
public class Tests 
{
    private Mock<IConfigHelper> configHelperMOCK;
    [SetUp]
    public void Setup()
    {
        configHelperMOCK = new Mock<IConfigHelper>();
    }

    [Test]
    public void serviceIsBPManagementForValidSource()
    {
        //Arrange
        string sectionName = "sectionName/sectionElement";
        string clinicalElementName = "ClinicalSystem";
        string clinicalElementValue = "Zedmed";
        configHelperMOCK.Setup(s => s.GetConfiguration(sectionName, clinicalElementName)).Returns(clinicalElementValue);

        //act
        // the call to myRealClass

        //assert
        // test assertions
    }
}

我遇到的问题是这一行:

ConfigHelper configUtil = new ConfigHelper(); //NOT BEING MOCKED

我无法让moq模拟对象。 我不希望代码读取配置文件。我希望moq这个ConfigHelper

的实例

3 个答案:

答案 0 :(得分:1)

你不能包装静态类/方法,但你可以重定向它

public static class UtilSvc
{
     static UtilSvc()
     {
         CreatorFunc = () => new ConfigHelper();
     }

     public static Func<IConfigHelper> CreatorFunc { get; set; }

     public static string GetConfigurationValue()
     {
         var configUtil = CreatorFunc();
         return configUtil.GetConfiguration("sectionName/sectionElement", 
                                            "ClinicalSystem");
     }
}

然后在测试中

//...
private Mock<IConfigHelper> configHelperMOCK;

[SetUp]
public void Setup()
{
    configHelperMOCK = new Mock<IConfigHelper>();
    UtilService.CreatorFunc = () => configHelperMOCK.Object;
}
//...

答案 1 :(得分:0)

你不能模拟静态类。我宁愿建议将IConfigHelper注入myRealClass。这是解决依赖关系和使用DI的常用方法。

public class myRealClass
{
  private IConfigHelper _configHelper;  

  public myRealClass(IConfigHelper configHelper)
  {
     _configHelper = configHelper;
  }

  public string myworkingMethod()
  {
     var retValue = String.Empty;
     retValue = _configHelper.GetConfigurationValue();
     return retValue;
   }
}

答案 2 :(得分:0)

避免将代码耦合到静态类,这在大多数情况下会导致代码难以维护和测试。

关注Explicit Dependencies Principle

  

方法和类应明确要求(通常通过   方法参数或构造函数参数)任何协作对象   他们需要才能正常运作。

阅读文章。它简短而且信息量很大。

如果你想保留静态类,那么你将静态类包装在抽象之后。

public interface IUtilSvc {
    string GetConfigurationValue();
}

public class utilSvcWrapper : IUtilSvc {
    public string GetConfigurationValue() {
        return utilSvc.GetConfigurationValue(); //Calling static service
    }
}

或者另一种选择是,如果可以将依赖类注入到依赖类中,则utlSvc不必是静态的

public class utilSvc : IUtilScv {
    private readonly IConfigHelper configUtil;

    public utilSvc(IConfigHelper configHelper) {
        configUtil = configHelper;
    }

    public string GetConfigurationValue() {
        return configUtil.GetConfiguration("sectionName/sectionElement", "ClinicalSystem");
    }
}

IUtilScv注入依赖类,使其不再依赖于静态类。

public class myRealClass {
    private readonly IUtilScv utilSvc;

    //Explicit dependency inject via constructor
    public myRealClass(IUtilScv utilSvc) {
        this.utilSvc = utilSvc;
    }

    public string myworkingMethod() {
        var retValue = utilSvc.GetConfiguration();
        return retValue;
    }
}

在这种情况下,您在测试时甚至不需要IConfigHelper,因为它也被抽象掉了。而且您只需要模拟测试所需的依赖项。

[TestFixture(TestName = "Tests")]
public class Tests {
    private Mock<IUtilScv> utilScvMOCK;

    [SetUp]
    public void Setup() {
        utilScvMOCK = new Mock<IUtilScv>();
    }

    [Test]
    public void serviceIsBPManagementForValidSource() {
        //Arrange
        var expectedClinicalElementValue = "Zedmed";
        utilScvMOCK
            .Setup(s => s.GetConfiguration())
            .Returns(expectedClinicalElementValue)
            .Verifiable();            

        var sut = new myRealClass(utilScvMOCK.Object);

        //Act
        var actualClinicalElementValue = sut.myworkingMethod();

        //Assert
        configHelperMOCK.Verify();
        Assert.AreEqual(expectedClinicalElementValue, actualClinicalElementValue);
    }
}