Pointers need on first test with NUnit and MVC Contrib - asp.net-mvc

I'm using ASP.NET MVC 2, NUnit, Moq and MVC Contrib. I have written my first unit test ever, and I have a couple of questions regarding this test. My scenario is that I have an Index view. On this view I have a grid that displays all the news items.
Here is my INewsRepository class:
public interface INewsRepository
{
IEnumerable<News> FindAll();
}
My test class with the test method:
public class NewsControllerTest :TestControllerBuilder
{
private Mock<INewsRepository> mockNewsRepository;
private NewsController newsController;
[SetUp]
public void Init()
{
mockNewsRepository = new Mock<INewsRepository>();
newsController = new NewsController(mockNewsRepository.Object);
InitializeController(newsController);
}
[Test]
public void NewsController_Index()
{
// Arrange
var news = new Mock<IEnumerable<News>>();
mockNewsRepository.Setup(r => r.FindAll()).Returns(news.Object).Verifiable();
// Act
ActionResult actual = newsController.Index();
// Assert
mockNewsRepository.Verify();
actual
.AssertViewRendered()
.ForView("Index")
.WithViewData<News[]>()
.ShouldBe(news);
}
}
My view:
public ActionResult Index()
{
FakeNewsRepository fakeNewsRepository = new FakeNewsRepository();
IEnumerable<News> news = fakeNewsRepository.FindAll();
return View(news);
}
I need some pointers on the way that I did it. Am I in the correct direction? What should I add, what should I leave out? I want to do unit testing, am I mixing it with integration testing? Any extra advice would be appreciated.
When I run this test in the NUnit GUI console then I get an error back and I'mnot sure what it means:
MyProject.Web.Tests.Controllers.NewsControllerTest.NewsController_Index:
Moq.MockVerificationException : The following setups were not matched:
INewsRepository r => r.FindAll()

public ActionResult Index()
{
FakeNewsRepository fakeNewsRepository = new FakeNewsRepository();
IEnumerable<News> news = fakeNewsRepository.FindAll();
return View(news);
}
You cannot mock the repository that is hardcoded like this in your action. You are instantiating it inside the action, you will never be able to unit test this and mock the repository. The repository needs to be injected as a dependency. You could use an interface and pass this interface to the constructor of your controller:
public class HomeController: Controller
{
private readonly IRepository _repository;
public class HomeController(IRepository repository)
{
_repository = repository;
}
public ActionResult Index()
{
IEnumerable<News> news = _repository.FindAll();
return View(news);
}
}
Now in your unit test you could pass the mocked instance of your repository to the controller constructor and define expectations.
Also notice that MVCContrib.TestHelper is designed to work with Rhino Mocks. I am not quite sure whether it works fine with Moq.

Related

How can I use Moq to test my Index action that returns list from the database?

I am learning to use unit testing and Moq for ASP.NET MVC 5. I am trying to write my first unit test for the index action of one of my controllers.
Here is the code for the index action.
[Authorize]
public class ExpenseController : Controller
{
private ApplicationDbContext db = new ApplicationDbContext();
// GET: /Expense/
public ActionResult Index()
{
return View(db.Expenses.ToList().Where(m => m.ApplicationUserId == User.Identity.GetUserId()));
}
}
All I want to do is just check that the returned view is not null
Something like this
[TestMethod]
public void ExpenseIndex()
{
// Arrange
ExpenseController controller = new ExpenseController();
// Act
ViewResult result = controller.Index() as ViewResult;
// Assert
Assert.IsNotNull(result);
}
Of course, this is not working because of the connecting to the database and the using of the ApplicationUserId so would you guys help me to moq and unit test this action or recommend me a tutorial where I can get familiar with mocking in ASP.NET MVC.
One way to do this is to abstract encapsulate the dependency in a virtual method, for example: Create a virtual method that returns the user expenses, now your controller should look like:
public class ExpenseController : Controller
{
private ApplicationDbContext db = new ApplicationDbContext();
// GET: /Expense/
public ActionResult Index()
{
return View(GetUserExpenses());
}
protected virtual List<Expense> GetUserExpenses()
{
return db.Expenses.ToList().Where(m => m.ApplicationUserId == User.Identity.GetUserId());
}
}
Then, create a stub class, that is derived from your controller, and override the GetUserExpenses() method. It should look like:
public class ExpenseControllerStub : ExpenseController
{
protected override List<Expense> GetUserExpenses()
{
return new List<Expense>();
}
}
Now in your unit test, create the instance from ExpenseControllerStub not from ExpenseController, and it should work:
[TestMethod]
public void ExpenseIndex()
{
// Arrange
ExpenseControllerStub controller = new ExpenseControllerStub();
// Act
ViewResult result = controller.Index() as ViewResult;
// Assert
Assert.IsNotNull(result);
}
This is how to do it manually. If you need to use a mocking framework for this, you will need to make GetUserExpenses() public not protected, then make a setup to return an empty expenses list, something like:
var mock = new Moq.Mock<ExpenseController>();
mock.Setup(m => m.GetUserExpenses().Returns(new List<Expense>());
But I don't prefer to make this method public! may be there is a way for Moq to configure/setup protected methods, but I am not aware of it.
Edit: A more better solution is to totally abstract the Expenses repository, in this case mocking it will be straight forward.
Another solution is to inject the DbContext to the controller constructor, and use a mocking framework to mock it and the Expenses DbSet. You can find a sample for doing this here
Edit#2: You may also use TestStack.FluentMVCTesting or MvcContrib.TestHelper to make you MVC testing easier.

Build model in unit test

Just wanted some guidance how would I go about unit testing the following action:
public ActionResult Index()
{
var model = _resolver.GetService<ISignUpViewModel>();
model.Location = _resolver.GetService<ILocations>().getLocations(string area);
return PartialView("Login", model);
}
private IDependencyResolver _resolverMock;
[TestMethod]
public void SignUpTest()
{
var _resolverMock = new Mock<IDependencyResolver>();
var ctrl = new HomeController(_resolverMock.Object);
var signUpMock = new Mock<ISignUpViewModel>();
var LocationsMock = new Mock<ILocations>();
_resolverMock.Setup(m => m.GetService(It.IsAny<Type>())).Returns(
signUpMock.Object);
_resolverMock.Setup(m => m.GetService(It.IsAny<Type>())).Returns(
LocationsMock.Object);
DependencyResolver.SetResolver(resolverMock.Object);
ctrl.Index();
ctrl.ViewData.Model = signUpMock;
}
How do you build up the model in the unit test?
Also how do I call the getLocations method from the resolver?
Unsure on how to do this?
Your home controller is not dependent on an IDependencyResolver as per your code. It is in fact dependent on an ISignUpViewModel. So you can either pass one of those into the constructor or an ISignUpViewModelFactory. So I would refactor the model resolution out into a factory class:
public class HomeController {
private readonly ISignUpViewModelFactory _modelFactory;
public HomeController(ISignUpViewModelFactory modelFactory){
_modelFactory = modelFactory;
}
public ActionResult Index()
{
return PartialView("Login", _modelFactory.Create(area));
}
}
public interface ISignUpViewModelFactory {
ISignUpViewModel Create(string area);
}
public class ProductionSignUpViewModelFactory : ISignUpViewModelFactory
{
public ISignUpViewModel Create(string area){
// create and return your models here
// if you still have to use a service locator in this factory then
// refactor some more until you get these dependencies out in the open.
}
}
public class MockSignUpViewModelFactory : ISignUpViewModelFactory
{
public ISignUpViewModel Create(string area){
return new SignUpViewModel();
}
}
In production you have your IOC inject an instance of ProductionSignUpViewModelFactory. In test, you pass in a MockSignUpViewModelFactory.
The difference is that using this method you are only testing the action (i.e. the unit) whereas using your current method you are testing the action AND your servicelocator _resolver plus you've obscured the actual dependency i.e. ISignUpViewModel not IDependencyResolver.
As per the comments in ProductionSignUpViewModelFactory, if you have to inject an IDependencyResolver into that factory to make it work then you're probably still doing it wrong. You then need to look at what ProductionSignUpViewModelFactory needs to create an instance of ISignUpViewModel and inject that not an IDependencyResolver.
Eventually you'll get to the top of your dependency chain and you'll find unit testing becomes very, very easy. It's even easier if you build the tests first i.e. TDD. :)

Initialize BaseController's fields using HttpContext, controller design

I need to setup a policy in base controller that applies to all controller instance, like below:
public class BaseController : Controller
{
private IPolicy Policy;
public BaseController()
{
this.Policy= new Policy(HttpContext);
}
}
Within the Policy class, I need to do something like:
this.httpContextBase.User.
Questions: (Update)
What is the better way to design the BaseController in terms of using HttpContext and Unit test.
What is the correct way to unit test HttpContext?
Absolutely no way. You are using the HttpContext inside the constructor of a controller when this context is still not initialized. Not only that this code cannot be tested but when you run the application it will also crash with NRE. You should never use any HttpContext related stuff in a constructor of a controller.
One possibility is to refactor your code and perform this inside the Initialize method:
public class BaseController : Controller
{
private IPolicy Policy;
protected override void Initialize(RequestContext requestContext)
{
base.Initialize(requestContext);
this.Policy = new Policy(HttpContext);
}
}
This being said, that's not the approach I would recommend. I would recommend you using dependency injection instead of service location which is considered by many as an anti-pattern.
So:
public abstract class BaseController : Controller
{
protected IPolicy Policy { get; private set; }
protected BaseController(IPolicy policy)
{
Policy = policy;
}
}
Now, all that's left is to configure your favourite Dependency Injection framework to inject the correct instance into the constructor. For example with Ninject.Mvc3 this is achieved with a single line of code:
kernel.Bind<IPolicy>().To<Policy>();
Now you can feel more than free to mock this IPolicy in your unit test without even caring about any HttpContext.
For example let's suppose that you have the following controller that you want to unit test:
public class FooController : BaseController
{
public FooController(IPolicy policy): base(policy)
{ }
[Authorize]
public ActionResult Index()
{
Policy.DoSomething();
return View();
}
}
Now, all that you need to do is pick up your favorite mock framework (Rhino Mocks in my case) and do the mocking:
[TestMethod]
public void Index_Action_Should_DoSomething_With_The_Policy()
{
// arrange
var policyStub = MockRepository.GenerateStub<IPolicy>();
var sut = new FooController(policyStub);
// act
var actual = sut.Index();
// assert
Assert.IsInstanceOfType(actual, typeof(ViewResult));
policyStub.AssertWasCalled(x => x.DoSomething());
}

Testing domain when using using repository pattern

I'm getting my feet wet with unit testing (TDD). I have a basic repository pattern I'm looking to test and I'm not really sure I'm doing things correctly. At this stage I'm testing my domain and not worrying about controllers and views. To keep it simple here is a demo project.
Class
public class Person
{
public int PersonID { get; set; }
public string Name{ get; set; }
}
Interface
public interface IPersonRepository
{
int Add(Person person);
}
Concrete
public class PersonnRepository : IPersonRepository
{
DBContext ctx = new DBContext();
public int Add(Person person)
{
// New entity
ctx.People.Add(person);
ctx.SaveChanges();
return person.id;
}
}
I've added NUnit and MOQ to my test project and want to know how to properly test the functionality.
I'm not sure it's right but after reading some blogs I ended up creating a FakeRepository, however if I test based on this, how is that validating my actual interface?
public class FakePersonRepository
{
Dictionary<int, Person> People = new Dictionary<int, Person>();
public int Add(Person person)
{
int id = People.Count + 1;
People.Add(id, person);
return id;
}
}
then tested with
[Test]
public void Creating_A_Person_Should_Return_The_ID ()
{
FakePersonRepository repository = new FakePersonRepository();
int id = repository.Add(new Person { Name = "Some Name" });
Assert.IsNotNull(id);
}
Am I anywhere close to testing in the correct manor?
I'd like to test things like not passing a name causes error etc in the future.
Am I anywhere close to testing in the correct manor?
I am afraid that you are not. The idea of having an interface is that it allows you to decouple other code that uses a repository such your controller and be able to unit test it in isolation. So let's suppose that you have the following controller that you want to unit test:
public class PersonController : Controller
{
private readonly IPersonRepository _repo;
public PersonController(IPersonRepository repo)
{
_repo = repo;
}
[HttpPost]
public ActionResult Create(Person p)
{
if (!ModelState.IsValid)
{
return View(p);
}
var id = _repo.Add(p);
return Json(new { id = id });
}
}
Notice how the controller doesn't depend on a specific repository implementation. All needs is that this repository implements the given contract. Now we could use a mocking framework such as Moq in the unit test to provide a fake repository and make it behave as we like in order to test the 2 possible paths in the Create action:
[TestMethod]
public void PersonsController_Create_Action_Should_Return_View_And_Not_Call_Repository_If_ModelState_Is_Invalid()
{
// arrange
var fakeRepo = new Mock<IPersonRepository>();
var sut = new PersonController(fakeRepo.Object);
var p = new Person();
sut.ModelState.AddModelError("Name", "The name cannot be empty");
fakeRepo.Setup(x => x.Add(p)).Throws(new Exception("Shouldn't be called."));
// act
var actual = sut.Create(p);
// assert
Assert.IsInstanceOfType(actual, typeof(ViewResult));
}
[TestMethod]
public void PersonsController_Create_Action_Call_Repository()
{
// arrange
var fakeRepo = new Mock<IPersonRepository>();
var sut = new PersonController(fakeRepo.Object);
var p = new Person();
fakeRepo.Setup(x => x.Add(p)).Returns(5).Verifiable();
// act
var actual = sut.Create(p);
// assert
Assert.IsInstanceOfType(actual, typeof(JsonResult));
var jsonResult = (JsonResult)actual;
var data = new RouteValueDictionary(jsonResult.Data);
Assert.AreEqual(5, data["id"]);
fakeRepo.Verify();
}
You need to make your DBContext injectable by extracting an interface for it:
public interface IDBContext{
IList<Person> People {get;} // I'm guessing at the types
void SaveChanges();
// etc.
}
Then inject that into your concrete class:
public class PersonRepository : IPersonRepository
{
IDBContext ctx;
public PersonRepository(IDBContext db) {
ctx = db;
}
public int Add(Person person)
{
// New entity
ctx.People.Add(person);
ctx.SaveChanges();
return person.id;
}
}
Your test would then look like:
[Test]
public void Creating_A_Person_Should_Return_The_ID ()
{
Mock<IDBContext> mockDbContext = new Mock<IDBContext>();
// Setup whatever mock values/callbacks you need
PersonRepository repository = new PersonRepository(mockDbContext.Object);
int id = repository.Add(new Person { Name = "Some Name" });
Assert.IsNotNull(id);
// verify that expected calls are made against your mock
mockDbContext.Verify( db => db.SaveChanges(), Times.Once());
//...
}
I'd personally look at writing an "integration test" for this, i.e. one that hits a real (ish) database as your data access layer should not contain any logic which makes testing in isolation worthwhile.
In this case you will require a database up and running. This could be a developer database already set up somewhere, or an in-memory database started as part of the tests arrange.
The reason for this is that I find (pure) unit tests of the DAL generally end up as proof you can use a mock framework and little more and don't end up giving you much confidence in your code.
If you are completely new to unit tests and don't have colleges on hand to help set up the environment required for DAL testing you then I'd recommend you leave testing the DAL for now and concentrate on the business logic as this is where you will get the biggest bang for your buck and will make it easier see how the tests will help you.

How to use Moq framework correctly - basic question

I've never used any Mock frameworks and actually new to ASP.NET MVC, testing and all this related stuff.
I'm trying to figure out how to use Moq framework for testing, but can't make it work. that's what I have at the moment: My repository interface:
public interface IUserRepository {
string GetUserEmail();
bool UserIsLoggedIn();
ViewModels.User CurrentUser();
void SaveUserToDb(ViewModels.RegisterUser viewUser);
bool LogOff();
bool LogOn(LogOnModel model);
bool ChangePassword(ChangePasswordModel model);
}
My Controller constuctor, I'm using Ninject for injection, it works fine
private readonly IUserRepository _userRepository;
public HomeController(IUserRepository userRepository) {
_userRepository = userRepository;
}
Simplest method in controller:
public ActionResult Index() {
ViewBag.UserEmail = _userRepository.GetUserEmail();
return View();
}
And my test method:
[TestMethod]
public void Index_Action_Test() {
// Arrange
string email = "test#test.com";
var rep = new Mock<IUserRepository>();
rep.Setup(r => r.GetUserEmail()).Returns(email);
var controller = new HomeController(rep.Object);
// Act
string result = controller.ViewBag.UserEmail;
// Assert
Assert.AreEqual(email, result);
}
I assume that this test must pass, but it fails with message Assert.AreEqual failed. Expected:<test#test.com>. Actual:<(null)>.
What am I doing wrong?
Thanks
Simple - you do not do Act part correctly. Fisrt you should call Index() action of the controller, and then Assert ViewBag.UserEmail correctness
// Act
controller.Index();
string result = controller.ViewBag.UserEmail;
By the way, advice - Using ViewBag is not the good practice. Define ViewModels instead

Resources