如何模拟container.Resolve <type>()</type>

时间:2009-11-24 12:44:34

标签: c# moq ioc-container

我有类似的东西

public class HomeController
{
   public ActionResult Index()
   {
      var x = Container.Resolve<IOrganisationService>();
   }
}

当单元测试时,当容器尝试解析时,我得到一个空引用异常
谁知道如何模拟Container.Resolve()?

4 个答案:

答案 0 :(得分:7)

你不能,因为有问题的Resolve方法是静态方法。这是静态类型在单元测试中被认为是 evil 的众多原因之一(因此也是代码的一般可组合性)。

您似乎正在应用称为服务定位器的(反)模式,并且您目前遇到了与之相关的许多问题之一。

更好的解决方案是使用构造函数注入,如下所示:

public class HomeController
{
   private readonly IOrganisationService organisationService;

   public HomeController(IOrganisationService organisationService)
   {
       if (organisationService == null)
       {
           throw new ArgumentNullException("organisationService");
       }

       this.organisationService = organisationService;
   }

   public ActionResult Index()
   {
      var x = this.organisationService;
      // return result...
   }
}

您现在可以让您选择的DI容器从外部解析HomeController实例。这是一个更灵活的解决方案。

答案 1 :(得分:5)

问题是,为什么要以这种方式解决它?如果您反而注入了依赖项,那么您可以轻松地模拟:

public class HomeController
{
    private readonly IOrganisationService organisationService;

    public HomeController(IOrganisationService organisationService)
    {
        this.organisationService = organisationService;
    }

   public ActionResult Index()
   {
      var x = this.organisationService;
   }
}

答案 2 :(得分:0)

某些容器(例如Windsor)有一个继承自接口的容器。如果你使用它,那么它是隐式可模拟的。如果您已经创建了一个可以调用resolve的静态方法,那么如上所述它不能被模拟是不可取的。如果您的容器没有从接口继承(或者您正在使用的服务定位器模式),则依赖于静态方法,然后更改实现,使其基于实例,因此可以模拟。

但是,我同意上述帖子。您不应该真正需要在代码中引用容器。这会将您的应用程序耦合到一个容器,这是您要使用容器避免的事情。

答案 3 :(得分:-1)

我做到了,就像这样:

//code inside the setup method
 var c = new Moq.Mock<IWindsorContainer>();
 var l = new Moq.Mock<ILookupService>();
 l.Setup(o => o.GetItems(It.IsAny<String>())).Returns(new List<LookupItem>());
 c.Setup(o => o.Resolve<ILookupService>()).Returns(l.Object);
 LocatorConfigurator.SetContainer(c.Object);