使用ninject在unittest中注入属性

时间:2014-08-21 15:21:03

标签: c# asp.net-mvc dependency-injection ninject

我有一个简单的标准MVC 5 Web应用程序控制器。我安装了MVC 5 Ninject nuget包。我创建了一个构造函数,并注入了我定义的接口。如果我创建了一个公共属性,也会注入它。

现在,当我创建一个unittest项目并想要测试mvc控制器时。我怎样才能做到这一点?我必须创建一个内核。内核已创建,如果我获得了我的IPersonComponent的实例,则会创建它。但为什么我的财产没有被注入?

我创建了两个选项,我都得到了空引用异常......

接口:

public interface IPersonComponent
{
    void DoSomething();
}

实现:

public class PersonComponent : IPersonComponent
{       public void DoSomething()
    {
        throw new NotImplementedException("The method is fired but not implemented");
    }
}

TestInitialize:

private IKernel _kernel;

[TestInitialize()]
public void Initialize()
{
    _kernel  = new StandardKernel();
}

选项1

运行良好的控制器:

public class HomeController : Controller
{
    private readonly IPersonComponent _component;

    public HomeController(IPersonComponent component)
    {
        _component = component;
    }
}

Unittest失败,因为PersonComponent为null:

[TestClass]
public class HomeControllerTest
{
    [Inject]
    public IPersonComponent PersonComponent { get; set; }

    [TestMethod]
    [ExpectedException(typeof(NotImplementedException))]
    public void Index()
    {
        // Arrange
        HomeController controller = new HomeController(PersonComponent);

        // Act
        ViewResult result = controller.Index() as ViewResult;

        // Assert
        Assert.IsNotNull(result);
    }
}

选项2

控制器:

public class HomeController : Controller
{

    [Inject]
    public IPersonComponent PersonComponent { get; set; }

    public HomeController()
    {

    }

    public ActionResult Index()
    {
        PersonComponent.DoSomething();

        return View();
    }
}

测试:

[TestMethod]
[ExpectedException(typeof(NotImplementedException))]
public void Index()
{
    // Arrange
    HomeController controller = new HomeController();

    // Act
    ViewResult result = controller.Index() as ViewResult;

    // Assert
    Assert.IsNotNull(result);
}

这有效: 但为什么它有效呢?为什么不自动注入?

[TestMethod]
public void TestDoSomething()
{
    var kernel = new StandardKernel();

    var comp = kernel.Get<IPersonComponent>();
    comp.DoSomething();
}

根据答案进行修改:

选项1

    [TestMethod]
    [ExpectedException(typeof(NotImplementedException))]
    public void Index()
    {
        _kernel.Inject(this);

        // Arrange
        HomeController controller = new HomeController(PersonComponent);

        // Act
        ViewResult result = controller.Index() as ViewResult;

        // Assert
        Assert.IsNotNull(result);
    }

选项2

[TestMethod]
[ExpectedException(typeof(NotImplementedException))]
public void Index()
{
    // Arrange
    HomeController controller = _kernel.Get<HomeController>();

    // Act
    ViewResult result = controller.Index() as ViewResult;

    // Assert
    Assert.IsNotNull(result);
}

1 个答案:

答案 0 :(得分:2)

在选项1中:MsTest不会调用Ninject来告诉它将服务注入到您的对象中。

在选项2中:您正在手动创建控制器(new HomeController()),并且您没有告诉Ninject将服务注入到您的对象中。

尽管Ninject所做的大部分内容似乎都是“神奇的”,但仍然需要调用它才能将值注入到组件中。 ASP.NET MVC有一个Ninject绑定的机制,因此控制器的构造由Ninject自动处理。这给你的印象是Ninject能够毫不费力地将值注入任何东西。但是MSTest没有类似的机制,所以你必须手动完成这项工作。

如果您可以访问已配置的ninject内核,则可以说:

HomeController controller = kernel.Get<HomeController>();

或者,在选项1中,您可以说:

public HomeControllerTest()
{
    kernel.Inject(this); // populate my [Inject] properties
}

我应该提一下,如果您是基于真实绑定注入依赖项,那么您并不是真正编写“单元测试”,而是“自动验收测试”。如果要测试独立于其依赖项的控制器操作的行为,请学习如何“模拟”其依赖项。