我有一个简单的标准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);
}
答案 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
}
我应该提一下,如果您是基于真实绑定注入依赖项,那么您并不是真正编写“单元测试”,而是“自动验收测试”。如果要测试独立于其依赖项的控制器操作的行为,请学习如何“模拟”其依赖项。