I have a simple contoller of a standard MVC 5 web application. I installed the MVC 5 Ninject nuget package. I created a constructor and the interface that I have defined is injected. If I create a public property this is also injected.
Now when I create a unittest project and want to test the mvc controller. How can I do that? I have to create a kernel. The kernel is created and if I get an instance of my IPersonComponent it is created. But why doesn't my property not get injected?
I created two options and both I get nullreference exception...
Interface:
public interface IPersonComponent
{
void DoSomething();
}
Implementation:
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();
}
Option 1
Controller that is working great:
public class HomeController : Controller
{
private readonly IPersonComponent _component;
public HomeController(IPersonComponent component)
{
_component = component;
}
}
Unittest fails because PersonComponent is 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);
}
}
Option 2
Controller:
public class HomeController : Controller
{
[Inject]
public IPersonComponent PersonComponent { get; set; }
public HomeController()
{
}
public ActionResult Index()
{
PersonComponent.DoSomething();
return View();
}
}
Test:
[TestMethod]
[ExpectedException(typeof(NotImplementedException))]
public void Index()
{
// Arrange
HomeController controller = new HomeController();
// Act
ViewResult result = controller.Index() as ViewResult;
// Assert
Assert.IsNotNull(result);
}
This works:
But why does it work? Why isn't it injected automatically?
[TestMethod]
public void TestDoSomething()
{
var kernel = new StandardKernel();
var comp = kernel.Get<IPersonComponent>();
comp.DoSomething();
}
Edit based on the answer:
Option 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);
}
Option 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);
}
In option 1: MsTest does not invoke Ninject to tell it to inject services into your objects.
In option 2: You are creating the controller manually (new HomeController()), and you're not telling Ninject to inject services into your objects.
Although much of what Ninject does seems "magical," it still has to be invoked in order to be able to inject values into your components. ASP.NET MVC has a mechanism that Ninject ties itself into, so that construction of controllers is handled by Ninject automatically. This gives you the impression that Ninject is able to inject values into anything without effort. But MSTest does not have a similar mechanism, so you have to do some of this work manually.
If you have access to the ninject kernel that's been configured, you can say:
HomeController controller = kernel.Get<HomeController>();
Or, in option 1, you can say:
public HomeControllerTest()
{
kernel.Inject(this); // populate my [Inject] properties
}
I should mention that if you're injecting dependencies based on real bindings, you're not really writing "unit tests," but rather "automated acceptance tests." If you want to test the behavior of a controller action independent of its dependencies, learn how to "mock" its dependencies instead.
Related
Here is the code for the method that I'm developing the unit test for:
public ActionResult ItemsListing()
{
var itemsList = itemsRepository.GetItems(true);
if (itemsList.Count() > 0)
{
var itemsListVMs = Mapper.Map<IEnumerable<Item>, IEnumerable<itemsListingViewModel>>(itemsList);
return View(itemsListVMs);
}
else
{
return RedirectToAction("Home");
}
}
Following is the code from the mapping configuration file:
public static class MappingConfig
{
public static void RegisterMaps()
{
Mapper.Initialize(config =>
{
config.CreateMap<Item, itemsListingViewModel>();
});
}
}
And I have initialized mapper in the Application_Start() event of the Global.asax as below:
MappingConfig.RegisterMaps();
Below is the simple test method that I'm trying to run:
[TestMethod]
public void ItemsListing()
{
HomeController controller = new HomeController();
ViewResult result = controller.ItemsListing() as ViewResult;
Assert.IsNotNull(result);
}
It works fine when I simply run the application. But when I try to run the unit test method, it shows the mentioned error message. Can anyone help me to get over this issue? Thanks!
You need to create/register the mappings for your unit tests as well as the Application_Start() is not executed. It is associated with IIS, which is not running during unit tests. You have to manually call the mapping configurations.
[TestClass]
public class HomeControllerTests {
[ClassInitialize]
public static void Init(TestContext context) {
MappingConfig.RegisterMaps();
}
[TestMethod]
public void ItemsListing() {
HomeController controller = new HomeController();
ViewResult result = controller.ItemsListing() as ViewResult;
Assert.IsNotNull(result);
}
}
In the above test the mapping configuration is done in a method decorated with [ClassInitialize] attribute which
ClassInitializeAttribute Class
Identifies a method that contains code that must be used before any of
the tests in the test class have run and to allocate resources to be
used by the test class.
I have a controller called PostsController
public class PostsController : Controller
{
private readonly IPostsRepository repository;
public PostsController(IPostsRepository repository)
{
this.repository = repository;
}
public ViewResult Index()
{
var posts =
repository.All()
.OrderBy(post => post.PublishedAt);
return View("Index", posts.MapTo<PostViewModel>());
}
}
And a corresponding test fixture called PostsControllerTest
[TestFixture]
public class PostsControllerTest
{
private PostsController controller;
private Mock<IPostsRepository> repository;
[SetUp]
public void SetUp()
{
AutoMapperConfig.Configure();
repository = new Mock<IPostsRepository>();
controller = new PostsController(repository.Object);
}
[Test]
public void Index_ReturnsCorrectModel()
{
var actual = controller.Index().Model;
Assert.IsAssignableFrom<IEnumerable<PostViewModel>>(actual);
}
}
At the moment I am only testing that the controller returns the correct model type. Should I also stub the repository and test that the correct data is returned like this:
[Test]
public void Index_ReturnsCorrectModel()
{
var post = new Post
{
Slug = "continuing-to-an-outer-loop",
Title = "Continuing to an outer loop",
Summary = "When you have a nested loop, sometimes",
Content = "When you have a nested loop, sometimes",
PublishedAt = DateTime.Now.AddDays(7),
Tags = new Collection<Tag> { new Tag { Name = "Programming" } }
};
repository.Setup(repo => repo.All()).Returns(new[] { post });
var actual = controller.Index().Model as IEnumerable<PostViewModel>;
Assert.NotNull(actual);
Assert.AreEqual(1, actual.Count());
Assert.AreEqual(post.Title, actual.First().Title);
}
I feel so frustrated not knowing if I am unit testing properly. A clear explanation of which I approach I should take why would be very helpful.
I don't think you need to test the functionality of IPostRepository in this unit test. You should create a seperate unit test class for it.
Similarly the functionality of the MapTo<T> should be tested separately.
Unit tests should only test the functionality of the SUT (System Under Test) which in this case is the Index method of your PostsController class.
This is a simple method so the 2 things you want to be verifying in this unit test are:
1- The repository.All() method gets called once
2- Your view model is mapped correctly (which you are already doing)
This is how I would unit test this method:
[Test]
public void Index_ReturnsCorrectModel()
{
// Arrange
repository.Setup(repo => repo.All()).Returns(Enumerable.Empty<Post>());
// Act
var actual = controller.Index().Model;
// Assert
Assert.IsAssignableFrom<IEnumerable<PostViewModel>>(actual);
repository.Verify(repo => repo.All(), Times.Once);
}
Also, to minimize the effort required to arrange your unit test, use can use a library like AutoFixture which will automatically create the post object for you.
I have a controller in which there are multiple dependencies.And i have made a parameter constructor for that controller,which is taking the object of one of the main dependency(service layer).
public class ProductController
{
private IProductService _productService ;
public ProductController(IProductService productService)
{
this._productService = productService;
}
}
But in controller there are some methods which are working with multiple dependencies.
Public ActionResult GetProductDetails()
{
List<CategoryDto> catList = CategoryService.GetAllCategories()).ToList();
ProductViewModel model = new ProductViewModel
{
Name="",
Categories = catList
};
//other stuffs...
}
In the above method there is a different dependency CategoryService.And i want to ask to mock that dependency should i need to make different constructor or can i pass multiple dependency object to same constructor ?
Just inject all dependencies to class you are testing (SUT). You can use constructor or property injection. I would go with constructor injection:
public class ProductController
{
private IProductService productService;
private ICategoryService categoryService;
public ProductController(IProductService productService,
ICategoryService categoryService)
{
this.productService = productService;
this.categoryService = categoryService;
}
public ActionResult GetProductDetails()
{
var categories = categoryService.GetAllCategories().ToList();
// ...
}
}
In your tests you can use setup method (NUnit syntax) to create and pass mocked dependencies to SUT:
private ProductController controller;
private Mock<IProductService> productServiceMock;
private Mock<ICategoryService> categoryServiceMock;
[SetUp]
public void Setup()
{
productServiceMock = new Mock<IProductService>();
categoryServiceMock = new Mock<ICategoryService>();
controller = new ProductController(productServiceMock.Object,
categoryServiceMock.Object);
}
Then you can arrange any of this mocked object in test methods, just before exercising SUT:
[Test]
public void ShouldReturnProductDetails()
{
List<CategoryDto> categories = // ...
categoryServiceMock.Setup(cs => cs.GetAllCategories()).Returns(categories);
var result = controller.GetProductDetails();
// Assert
}
Use the service locate pattern: the controller use a service locator to get service instances.
in the constructor:
public class ProductController
{
private IServiceLocator _serviceLocator;
public ProductController(IServiceLocator serviceLocator)
{
_serviceLocator= serviceLocator;
}
}
when you want to use a certain service:
ICategoryService categoryService = _serviceLocator.GetService(typeof(categoryService))
MSDN has an article: The Service Locator Pattern which explain whey use this pattern.
I have read Mark Seeman's article on auto-mocking and I'm now writing a re-usable windsor container based on that article.
My implementation of Mark's article (basically copied directly)
The main work is done in the AutoMoqResolver class. This will provide a mock whenever a class has a dependency on an interface:
public class AutoMoqResolver : ISubDependencyResolver
{
private readonly IKernel kernel;
public AutoMoqResolver(IKernel kernel)
{
this.kernel = kernel;
}
public bool CanResolve(
CreationContext context,
ISubDependencyResolver contextHandlerResolver,
ComponentModel model,
DependencyModel dependency)
{
return dependency.TargetType.IsInterface;
}
public object Resolve(
CreationContext context,
ISubDependencyResolver contextHandlerResolver,
ComponentModel model,
DependencyModel dependency)
{
var mockType = typeof(Mock<>).MakeGenericType(dependency.TargetType);
return ((Mock)this.kernel.Resolve(mockType)).Object;
}
}
The AutoMoqResolver is added to the container using the following implementation of the IWindsorInstaller interface:
public class AutoMockInstaller<T> : IWindsorInstaller
{
public void Install(
IWindsorContainer container,
IConfigurationStore store)
{
container.Kernel.Resolver.AddSubResolver(
new AutoMoqResolver(container.Kernel));
container.Register(Component.For(typeof(Mock<>)));
container.Register(Classes
.FromAssemblyContaining<T>()
.Pick()
.WithServiceSelf()
.LifestyleTransient());
}
}
Then my container simply runs the installer and it is ready to automatically provide mocks for any interface dependencies in unit tests:
public class AutoMockContainer<T> : WindsorContainer
{
public AutoMockContainer()
{
// simply run the auto-mock installer
this.Install(new AutoMockInstaller<T>());
}
}
Super!
I've tested this and my dependencies are happily mocked automatically so I then went to apply it to some real code. This is when I realised that the solution doesn't help me because of the pattern I tend to follow when testing a class. My specific issue is that I want to be able to auto-mock the SUT itself in order to verify that one method on the SUT is called from another.
My code that needs to be tested
I'll explain myself by way of an example. I am developing MVC code and I am supporting unobtrusive AJAX using the following general pattern:
public Class ExampleController : Controller
{
private IService service;
public ExampleController(IService service)
{
this.service = service;
}
public PartialViewResult DoSomethingWithAjax()
{
this.PerformTask();
return this.PartialView();
}
public RedirectToRouteResult DoSomethingWithoutAjax()
{
this.PerformTask();
return this.RedirectToAction("SomeAction");
}
protected virtual void PerformTask()
{
// do something here
}
}
My test pattern
So in order to verify that the PerformTask() method was called from DoSomethingWithAjax() or DoSomethingWithoutAjax(), I define a new TestableExampleController class like this:
public class TestableExampleController : ExampleController
{
public TestableExampleController(IService service) : base(service)
{
}
public virtual void PerfomTaskPublic()
{
base.PerfomTask();
}
protected override void PerformTask()
{
this.PerformTaskPublic();
}
}
I can then use TestableExampleController as my SUT so the following test will pass:
[TestMethod]
public void DoSomethingAjax_Calls_PerformTask()
{
//// Arrange
// create a mock TestableExampleController
var controllerMock = new Mock<TestableExampleController>();
controllerMock.CallBase = true;
// use the mock controller as the SUT
var sut = controllerMock.Object;
//// Act
sut.DoSomethingAjax();
//// Assert
controllerMock.Verify(x => x.PerformTaskPublic(), Times.Once());
}
My problem
Refactoring this test to use my AutoMockContainer class like this doesn't work:
[TestMethod]
public void DoSomethingAjax_Calls_PerformTask()
{
//// Arrange
// create a container
var container = new AutoMockContainer<TestableExampleController>();
// resolve a mock SUT using the container
var controllerMock = container.Resolve<Mock<TestableExampleController>>();
controllerMock .CallBase = true;
// use the mock controller as the SUT
var sut = controllerMock.Object;
//// Act
sut.DoSomethingAjax();
//// Assert
controllerMock.Verify(x => x.PerformTaskPublic(), Times.Once());
}
The test fails to create an instance of Mock<TestableExampleController> because it can't find a parameterless constructor.
Can not instantiate proxy of class: MyNamespace.TestableExampleController.
Could not find a parameterless constructor.
Parameter name: constructorArguments
My proposed solution
Ideally I would like to implement a wrapper class which can be registered with the container to automatically provide a mock for any component:
public class ComponentWrapper<T> where T : class
{
public ComponentWrapper(Mock<T> componentMock)
{
componentMock.CallBase = true;
this.ComponentMock = componentMock;
}
public Mock<T> ComponentMock { get; private set; }
public T Component
{
get { return this.ComponentMock.Object; }
}
}
I would like to be able to write the following test that passes:
[TestMethod]
public void DoSomethingAjax_Calls_PerformTask()
{
//// Arrange
// create a container
var container = new AutoMockContainer<TestableExampleController>();
// resolve a ComponentWrapper using the container
var wrapper = container.Resolve<ComponentWrapper<TestableExampleController>>();
//// Act
// call a method using the component
wrapper.Component.DoSomethingAjax();
//// Assert
// verify a method call using the mock
wrapper.ComponentMock.Verify(x => x.PerformTaskPublic(), Times.Once());
}
I can't quite get my head round how to achieve this and I've spent most of the day fiddling with new ISubDependencyResolver implementations but I just can't get this to work.
Hopefully my question is clear and the answer is actually relatively simple?
It turns out that AutoFixture.AutoMoq will do exactly what I want out of the box so thank you to TrueWill for pointing me in the right direction.
The following simple test will pass:
[TestMethod]
public void Run_Calls_DoSomethingProtected()
{
//// Arrange
// AutoMoqCustomization allows AutoFixture to
// be used an an auto-mocking container
var fixture = new Fixture().Customize(new AutoMoqCustomization());
// simply ask the fixture to create a mock
var sutMock = fixture.Create<Mock<TestableDummySystem>>();
//// Act
// exercise the mock object
sutMock.Object.Run();
//// Assert
// this verification passes!
sutMock.Verify(x => x.DoSomethingProtectedPublic());
}
I am attempting to unit test my controllers, and I am using the default MVC 3 AccountController unit tests as a basis. So far I have my controller, which looks like:
public partial class HomeController : MyBaseController
{
public HomeController(IUnitOfWork unitOfWork) { _unitOfWork = unitOfWork; }
public virtual ActionResult Index()
{
return View();
}
public virtual ActionResult About()
{
return View();
}
}
MyBaseController has the following code:
public class MyBaseController : Controller
{
public MyJobLeadsBaseController()
{
CurrentUserId = 0;
}
protected override void Initialize(RequestContext requestContext)
{
if (MembershipService == null) { MembershipService = new AccountMembershipService(); }
base.Initialize(requestContext);
// If the user is logged in, retrieve their login id
var user = MembershipService.GetUser();
if (user != null)
CurrentUserId = (int)user.ProviderUserKey;
}
public int CurrentUserId { get; set; }
public IMembershipService MembershipService { get; set; }
protected IUnitOfWork _unitOfWork;
}
Everything works correctly when I run the actual site, and breakpoints show that the Initialize() is correctly being triggered. However, the following unit test never runs the Initialize(RequestContext) method:
[TestMethod]
public void Index_Shows_When_Not_Logged_In()
{
// Setup
HomeController controller = new HomeController(_unitOfWork);
controller.MembershipService = new MockMembershipService(null);
SetupController(controller);
// Act
ActionResult result = controller.Index();
// Verify
Assert.IsNotNull(result, "Index returned a null action result");
Assert.IsInstanceOfType(result, typeof(ViewResult), "Index did not return a view result");
}
protected static void SetupController(Controller controller)
{
RequestContext requestContext = new RequestContext(new MockHttpContext(), new RouteData());
controller.Url = new UrlHelper(requestContext);
controller.ControllerContext = new ControllerContext
{
Controller = controller,
RequestContext = requestContext
};
}
Debugging through this unit test shows that at no point does the overridden MyBaseController.Initialize() get called at all. This causes issues where my CurrentUserId property is not being set in unit tests, but is being set on the live system.
What else do I have to do to trigger the Initialize() to be called?
When you make a request to a controller through a website the MVC framework picks up that request and runs it through a number of different steps. Somewhere in that pipeline of steps MVC knows that it must call the Initialize method so it finds the Initialize in your MyBaseController class and executes it. At this point all is well and everything works.
When you create a new instance of your HomeController in your test code you're simply creating a new instance of a class. You're not running that class through the MVC request pipeline and your test framework doesn’t know to execute the Initialize method so you get an error.
Personally I would look to test the Index action independently of the Initialize method. Your Index action above is empty so I can't see exactly what you're trying to do but if you are returning one view for logged in users and another for anonymous users I'd do something like this:
[TestMethod]
public void Index_Shows_When_Not_Logged_In(){
HomeController controller = new HomeController(_unitOfWork);
controller.CurrentUserId=0;
controller.Index();
//Check your view rendered in here
}
[TestMethod]
public void Some_Other_View_Shows_When_Logged_In(){
HomeController controller = new HomeController(_unitOfWork);
controller.CurrentUserId=12; //Could be any value
controller.Index();
//Check your view rendered in here
}
There are some pretty nifty test helpers in the MVC contrib project (http://mvccontrib.codeplex.com/) which allow you to do things like:
controller.Index().AssertViewRendered();
The constructor does not call Initialize. IIRC What calls initialize is the Execute/ExecuteCore method.
Here is the code from the MVC source:
protected virtual void Execute(RequestContext requestContext) {
if (requestContext == null) {
throw new ArgumentNullException("requestContext");
}
if (requestContext.HttpContext == null) {
throw new ArgumentException(MvcResources.ControllerBase_CannotExecuteWithNullHttpContext, "requestContext");
}
VerifyExecuteCalledOnce();
Initialize(requestContext);
using (ScopeStorage.CreateTransientScope()) {
ExecuteCore();
}
}
This is basically called from the MvcHandler in the BeginProcessRequest method.
Update:
RequestContext does not exist in a unit test, because you're not going through ASP.NET. If I remember correctly you'd need to mock it.
Another problem in using Initialize in a test is the membership provider, which I haven't used myself, but I would guess that AccountMembershipService would fail you in a test? It seems to me that this would create fragile tests. It would probably also slow you down if it has to contact a server, and might fail you on a CI server.
IMO,from a basic look around the Init method, it shouldn't be there. The easiest solution,without breaking anything, that comes to mind is using dependency injection to inject the CurrentUserId in the Controller ctor.
In the case where you "run the actual site" I suspect it calls the default constructor of your HomeController which in turn will call the base controller's correpsonding ctor.
Try modifying your custom ctor of public HomeController(IUnitOfWork unitOfWork) to
public HomeController(IUnitOfWork unitOfWork):base()
This will make sure to call the base controller's default ctor whenever it is called.