C# 模拟静态方法选项

C# 模拟静态方法选项,c#,asp.net-mvc,unit-testing,moq,C#,Asp.net Mvc,Unit Testing,Moq,我知道你不能用moq模拟静态方法,但我想知道我可能的选择是什么 我定义了一个控制器类 public class CustomerController : BaseController { private ICustomerManager cm; public CustomerController() : this(new CustomerManager()) { } public CustomerController(ICustomer

我知道你不能用moq模拟静态方法,但我想知道我可能的选择是什么

我定义了一个控制器类

public class CustomerController : BaseController
{
    private ICustomerManager cm;

    public CustomerController()
        : this(new CustomerManager())
    {
    }

    public CustomerController(ICustomerManager customerMan)
{
    cm = customerMan;
}

    public ActionResult EditContact(ContactVM model,  IEnumerable<HttpPostedFileBase> Files, PageAction pageAction)
    {
        if (ModelState.IsValid)
        {
            InitializeContactVM(model); //throws an error
        }
    }

    private void InitializeContactVM(ContactVM model)
    {
        model.Customer = cm.GetViewFindCustomerDetails((int)model.CustomerId);
        model.ContactClassificationList = AddBlankToList(SelectLists.ContactClassifications(false)); 
        model.ContactSourceList = AddBlankToList(SelectLists.ContactSources(false));
    }
}
在SelectList中调用GetContactClassifications的那一行,我觉得我应该能够模拟它(如果调用它的方法因为是静态的而无法模拟的话)。这个确实实现了一个接口

即使有某种方式可以模拟控制器中的私有方法(InitialiseContactVM),它也适合我


有什么方法可以实现这些目标吗?

应该重构
选择列表
类,以允许您插入
IReferenceDataManager
,而不是自己实例化一个。

理想情况下,您的DAL不应该由静态方法构成,但是提供服务的普通对象通过接口注入控制器或任何需要它的东西

但是,如果您不能/不想更改它,那么让您模拟它的“标准”方法是将静态方法调用与控制器解耦。可以通过将其包装在一个包含静态调用的类中并实现一个接口来完成,该接口被注入控制器中,并因此在测试中模拟出来。这有点类似于测试
MessageBox
调用或当前系统日期/时间

首先创建一个包含静态方法调用的接口:

public interface ISelectListsWrapper
{
    SelectList ContactClassifications(bool includeDeleted);
}
然后类将通过调用实际的静态方法来实现它:

public class SelectListsWrapper : ISelectListsWrapper
{
    public SelectList ContactClassifications(bool includeDeleted)
    {
        return SelectLists.ContactClassifications(includeDeleted);
    }
}
在控制器中,您在构造函数中获取该类的一个实例,将其保存到一个局部变量,并使用该局部变量通过包装器调用静态方法:

private readonly ISelectListsWrapper selectLists;

public CustomerController(ICustomerManager customerMan, ISelectListsWrapper selectLists)
{
    cm = customerMan;
    this.selectLists = selectLists;
}

private void InitializeContactVM(ContactVM model)
{
    model.Customer = cm.GetViewFindCustomerDetails((int)model.CustomerId);
    model.ContactClassificationList = AddBlankToList(this.selectLists.ContactClassifications(false)); 
    model.ContactSourceList = AddBlankToList(this.selectLists.ContactSources(false));
}

最后,在测试中,您只需通过包装器的模拟,并将其设置为返回对该测试有意义的任何内容。

我将尝试这样做,看看是否有进一步的进展如果我是您,我会认真考虑使
SelectList
不是一个静态类,而是在控制器中有一个实例。您应该看看如何使用依赖项注入。ASP.NETMVC4对此有很好的支持。Alejandro干杯,非常感谢您的详细回复,我已经做了修改,对我来说效果很好
public class SelectListsWrapper : ISelectListsWrapper
{
    public SelectList ContactClassifications(bool includeDeleted)
    {
        return SelectLists.ContactClassifications(includeDeleted);
    }
}
private readonly ISelectListsWrapper selectLists;

public CustomerController(ICustomerManager customerMan, ISelectListsWrapper selectLists)
{
    cm = customerMan;
    this.selectLists = selectLists;
}

private void InitializeContactVM(ContactVM model)
{
    model.Customer = cm.GetViewFindCustomerDetails((int)model.CustomerId);
    model.ContactClassificationList = AddBlankToList(this.selectLists.ContactClassifications(false)); 
    model.ContactSourceList = AddBlankToList(this.selectLists.ContactSources(false));
}