How to perform a Unit testing on MVC application?
I have created the Controller Location.
It has properties like LocationName,Area,City,PinCode.
Now, I want to perform unit test to check whether Location saves in DB or not.
How to check it.
I have go through tons of videos, every where they just put the Unit test of
Mathematical operations like adding,Dividing , subtracting....
I would like to know how to perform the Unit testing of Create method of MVC
I have code something like below
[HttpPost]
public ActionResult Create(Location location)
{
if (ModelState.IsValid)
{
db.Locations.Add(location);
db.SaveChanges();
return RedirectToAction("Index");
}
}
In order to make your code testable, you should abstract dependencies of controller. It's very handy to use Repository pattern to abstract data access. Inject your repository into controller:
public class LocationController : Controller
{
private ILocationRepository _locationRepository;
public LocationController(ILocationRepository locationRepository)
{
_locationRepository = locationRepository;
}
}
Now you can mock your repository. Here is sample test with Moq framework and MvcContrib:
// Arrange
Mock<ILocationRepository> repository = new Mock<ILocationRepository>();
var controller = new LocationController(repository.Object);
Location location = new Location("New York);
// Act
var result = controller.Create(location);
// Assert
result.AssertActionRedirect()
.ToAction<LocationController>(c => c.Index());
repository.Verify(r => r.Add(location));
repository.Verify(r => r.Save());
And you can implement code, which will pass this test:
[HttpPost]
public ActionResult Create(Location location)
{
if (ModelState.IsValid)
{
_locationRepository.Add(location);
_locationRepository.Save();
return RedirectToAction("Index");
}
}
You can read more on implementing repositories and testing MVC applications here:
Implementing the Repository and Unit of Work Patterns in an ASP.NET MVC Application. Nice feature also to have Unit of Work per request.
Related
Here is the scenario:
I'm writing a test for my controller and need to setup a view model titled CheckoutViewModel. My controller method, Products does not take CheckoutViewModel as a parameter, so I cannot pass it in that way.
Currently, the test fails returning a Null Exception because CheckoutViewModel is not getting set and called.
Question: How can I setup my CheckoutViewModel with data.
Error Details:
System.NullReferenceException
Object reference not set to an instance of an object
Current Test
[TestMethod]
public void Products_ProductControllerIsCalled_ReturnsViewWithProducts()
{
// Arrange
var currentSession = _autoMoqer.GetMock<ICurrentSession>().Object;
ProductController productController = new ProductController(currentSession);
var checkoutViewModel = new CheckoutViewModel
{
CheckoutId = new Guid()
};
// Act
ActionResult result = productController.Products();
// Assert
Assert.IsInstanceOfType(result, typeof(ViewResult));
}
Controller
[AccectReadVerbs]
public ActionResult Products()
{
CheckoutViewModel checkoutViewModel = GetCheckoutViewModel();
var checkoutId = checkoutViewModel.CheckoutId;
var result = _productOrchestrator.Products(checkoutId, currentSession)
return View(result);
}
Failing on this method
private CheckoutViewModel GetCheckoutViewModel()
{
if(Session["CheckoutViewModel"] == null)
{
return new CheckoutViewModel();
}
return (CheckoutViewModel)Session["CheckoutViewModel"];
}
If GetCheckoutViewModel has some dependencies on i.e services, dbConnection or other complex classes, you need to add a class with an interface, move the method for GetCheckOutViewModel to the class and take the new interface as a dependency to the controller. Then you need to mock the new interface.
Or edit your viewmodel to take interface dependencies on the stuff that stands in the way of unit testing, i.e the Session.
I think you could create some interface:
public interface ISessionManager
{
Session session {get; set;}
}
Then your controller constructor:
public ProductsController(ISessionManager sm)
{
_sessionManager = sm;
}
Then you can pass a mocked instance to your controller.
I'm guessing that the exceptions is due to the fact that when you're running the unit test there will not be any (webserver) session available. What you want do is to isolate your tests from any external dependencies - and a session state that is part of the webserver hosting environment would be an external dependency.
To solve this you need to either mock or stub out the Session object from your test. There are many ways to do this, but the easiest way would be to make Session a public property on the Controller. From your test you would then set the Session to an instance you create within your test.
when I applying the unit testing on Insert, Update and Delete operation. At that time the record inserted, updated and deleted in the database as well.
How it possible?
Can anyone give the solution to prevent the database effect?
Thanks,
Ideally you should be using mocking for scenarios where db interaction is there. Make sure you have separate out your db interaction logic and it is interface driven. Then you can create mock objects, wherein you define the expectation of your db interaction interfaces. So for example, if for example InsertSomething() method is called, what should be returned from this method? and so on. Sharing some links on details about unit testing and mocking.
https://msdn.microsoft.com/en-us/library/ff650441.aspx
https://github.com/Moq/moq4
http://www.developerhandbook.com/unit-testing/writing-unit-tests-with-nunit-and-moq/
Testing a MVC Controller fails with NULL reference exception
As another option, you can go for separate real database for testing purpose, if it is essential to execute tests against database. You can also, execute sql script at the start and after running the test to seed and clean data respectively to keep the database pristine
It is possible either by mocking your database (used in unit tests) or creating new database used only for testing purpose (integration tests).
I would recommend using these two approaches together. Remember, that amount of unit tests should be much bigger than integration tests.
Here is simple example how to mock database (using Moq library).
public class HomeController : Controller
{
private IUserRepository _repository;
public HomeController(IUserRepository repository)
{
_repository = repository;
}
public ActionResult AddNewUser(User newUser)
{
_repository.AddUser(newUser);
return View();
}
}
public interface IUserRepository
{
void AddUser(User newUser);
}
public class UserRepository : IUserRepository
{
private DBContext _context;
public UserRepository(DBContext context)
{
_context = context;
}
public void AddUser(User newUser)
{
_context.Users.Add(newUser);
}
}
[Test]
public void ShouldMockRepository()
{
// Given
var repository = new Mock<IUserRepository>();
var controller = new HomeController(repository.Object);
// When
controller.AddNewUser(new User());
// Then
repository.Verify(r => r.AddUser(It.IsAny<User>()), Times.Once);
}
In my current MVC application, I have architected a series of command objects to handle business actions. These business actions would be wrapped around service endpoints. These endpoints would also be consumed by an MVC frond-end & a windows app. Every business action will call into a DAO action, which in turn, calls into the required data access repositories to successfully perform the business action. I have listed an example action below.
Busines Action
public class CreateProjectAction
{
IInsertProjectDAOAction InsertProjectDAOAction { get; set; }
public void Execute()
{
// Does some business validation & other logic before
// calling the DAO action
InsertProjectDAOAction.Execute();
}
}
DAO Action
public interface IInsertProjectDAOAction
{
void Execute();
}
public class InsertProjectDAOAction
{
IProjectRepository ProjectRepository { get; set; }
public void Execute()
{
ProjectRepository.Insert();
}
}
Project Repository
public interface IProjectRepository
{
void Insert(Project proj);
// other db methods would be listed here
}
public class ProjectRepository
{
public void Insert(Project proj)
{
// Insert into the data store
}
}
Controller
[HttpPost]
public IHttpActionResult Create(NewProjectModel newProjectModel)
{
var cmdArgs = Mapper.Map<CreateProjectCommand.CreateProjectCommandArgs>(newProjectModel);
var action = new CreateProjectCommand(UserId, cmdArgs);
action.Execute();
if(action.IsSuccessful)
return Ok(project)
else
return InternalServerError(action.Exception);
}
Unit Test
public void InsertWith_ExistingProjectName_Returns_ServerError()
{
var arg = new CreateProjectCommandArgs(){ .... };
var cmd = CreateProjectAction(args);
action.Execute();
Assert.That(action.IsSuccessful, Is.False);
Assert.That(action.Exception, Is.TypeOf<UniqueNameExcepton>());
}
I am using Ninject to assist with the dependency injection between layers. I have a bunch of unit tests around the business 'CreateProjectAction' to test out expected behavior of that object. The business actions are wrapped around a series of Web API service endpoints. I would also like to write tests around my MVC controllers so that I can be sure they work as planned.
I like the architecure so far, but having trouble figuring out how to mock the DAO action properties in the business action when writing unit tests for the mvc controller. I'd love to hear suggestions, other viewpoints, etc ...
Your question is still a bit unclear. It seems likely for example that InsertProjectDAOAction implements the interface IInsertProjectDAOAction, even though your sample code doesn't indicate that it does. It's also unclear what CreateProjectCommand in your controller example is, since it isn't one of your example elements above it.
That said, one approach that you can take is to defer the creation of your commands out to a factory and inject the factory into your controller (through Ninject in your code and as a Mock in your unit tests). This allows you setup a mock chain. You mock the factory and have it return a mock of your action that you're interested in, which you can then setup to do whatever you want. At a very basic level, this might look like this:
public interface ICommandFactory {
IInsertProjectDAOAction CreateInsertProjectAction(int userId);
}
public class CommandFactory : ICommandFactory{
public IInsertProjectDAOAction CreateInsertProjectAction(int userId) {
return new InsertProjectDAOAction(/* userId???? */);
}
}
The controller would do something like this to use the factory:
public IHttpActionResult Create(/* ... */) {
var action = _commandFactory.CreateInsertProjectAction(1234);
action.Execute();
// ...
}
With a test looking something like:
[Test]
public void MyTest() {
var factoryMock = new Mock<ICommandFactory>();
var commandMock = new Mock<IInsertProjectDAOAction>();
factoryMock.Setup(x => x.CreateInsertProjectAction(It.IsAny<int>())).Returns(commandMock.Object);
commandMock.Setup(x => x.Execute()).Throws(new InvalidOperationException("Random failure"));
var controller = new MyController(factoryMock.Object);
try {
controller.Create(/* ... */);
Assert.Fail();
}
catch (InvalidOperationException ex) {
Assert.AreEqual("Random failure", ex.Message);
}
}
This is a general approach that you could take. However, as I've said, that might not be right for your situation, because your question is unclear. I've also ignored other issues about how you create / test your controller in general since that doesn't seem to be what your question is about...
Good day,
I am confused about unit testing the following:
1. MVC Controller:
[HttpGet]
public async Task<PartialViewResult> DoExternalCallsAsync()
{
var model = new MyModel();
await MyStaticLibrary.DoExternalWorkAsync(Server.MapPath("~\\") + "WorkSource.txt", model);
return PartialView("_MyResults", model);
}
2. Static library:
public static async Task DoExternalWorkAsync(string sourcePath, MyModel model)
{
var externalCalls =
System.IO.File.ReadAllLines(sourcePath)
.Where(line => (!string.IsNullOrEmpty(line) && line.First() != '#'))
.Select(p => DoExternalCall(p, model));
await Task.WhenAll(externalCalls);
}
private static async Task DoExternalCall(string urlPath, MyModel model)
{
var result = await GetExternalApiResultAysnc(urlPath);
// some code here...
return;
}
Basically, all that the controller does is call an external API, which does some work and returns a result or throws an error.
There are no interfaces or abstract classes with the external Api.
How do I go about unit testing this?
N. B. I am not at liberty to change the design of the external Api.
Thanks,
Using static classes or methods in your code makes that code hard to properly unit test. See Is static universally “evil” for unit testing and if so why does resharper recommend it?, Static class/method/property in unit test, stop it or not, When to use static classes in C#.
Wrap the static API call class into an instance class with an interface:
public interface IMyLibrary
{
Task DoExternalWorkAsync();
}
public class MyStaticLibrary : IMyLibrary
{
public async Task DoExternalWorkAsync(string sourcePath, MyModel model)
{
return await MyStaticLibrary.DoExternalWorkAsync(sourcePath, model);
}
}
Then you can inject an instance into the controller's constructor.
Because the only thing that should be unit tested in this controller action method:
Does the code call the library with the proper arguments?
Does the method return the proper object?
During testing, you can inject a mocked IMyLibrary in the controller and verify that the controller correctly calls the mock, and you can verify that the result is a PartialViewResult containing whatever it should contain.
The library is an implementation detail of performing some unit of work. It should be abstracted out completely. If you want to run integration tests, that's a different style of testing completely.
So I am pretty new to testing, I never really done much, so my I may lack some fundamentals.
Question 1:
I am using ASP MVC4 and want to use Moq with my unit test case. After reading there are a lot of example, I see that I am suppose to have an interface. Where exactly should this go? In the controller folder, the test project?
Question 2
If I am testing a method in my controller and it has multiple calls to the db how would I Moq that
public ActionResult Index()
{
var model = new myModel();
var pList = new List<myModel.pType>();
var sList = new List<myModel.sType>();
var results = Class1.FetchPData(); // how would I mock this
var result1 = Class1.FetchSData(); // how would I mock this
for (int i = 0; i < results.Count(); i++)
{
... do stuff
}
for (int j = 0; j < result1.Count(); j++)
{
..do stuff
}
return View("Index", model);
}
Will I have to create another method where it contains the same logic, but I will have to pass in "Mock Object" as a param to the method, and have that as an implementable method in my interface? Or re-implement my method?
After reading there are a lot of example, I see that I am suppose to
have an interface. Where exactly should this go? In the controller
folder, the test project?
There is no rule where to keep interfaces, but usually you keep them closely to code which uses them. Usually I have domain classes and services in separate assembly with repository interfaces defined there. Then I reference this assembly by Data Access assembly which have implementations of repository interfaces. And last step - I reference both assemblies from web application.
If I am testing a method in my controller and it has multiple calls to
the db how would I Moq that
Remember, good unit tests should be Fast, Isolated, Repeatable, Self-Verifying, and Timely (FIRST). Having database calls in controller does not allow you to run tests fast (database calls are very slow comparing to in-memory code), to test controller in isolation and make tests always repeatable. Also your controller simply does to many things (i.e. violates SRP principle) - it gets user input, makes database queries and prepares model for view.
So, in order to separate responsibilities and make your controller testable, you should
extract data-access related code to separate class (usually such classes called repositories). And create abstraction which will specify API between controller and repository:
public interface IYourRepository
{
IEnumerable<pType> FetchPData();
IEnumerable<sType> FetchSData();
}
Then make your controller depend on this abstraction (inverse dependency), and inject repository to controller (you can use Ninject, Unity or other dependency injection framework):
IYourRepository _repository;
public YourController(IYourRepository repository)
{
_repository = repository;
}
public ActionResult Index()
{
var model = new myModel();
foreach (var p in _repository.FetchPData())
// do stuff
foreach (var s in _repository.FetchSData())
// do stuff
return View("Index", model);
}
That will allow you to mock repository easily and provide mocked object to controller:
var repositoryMock = new Mock<IYourRepository>();
repositoryMock.Setup(r => r.FetchPData()).Returns(pList);
repositoryMock.Setup(r => r.FetchSData()).Returns(sList);
var controller = new YourController(repositoryMock.Object);
var result = controller.Index();
// Assertions