I am using ASP.NET MVC 3, MVCContrib, NUnit and Rhino Mocks. I have posted this but could not get an answer. People are focusing more on my coding that helping me get a decent answer to get this test to pass.
I am trying to test my Edit view. I'm not sure how to code the test for the view. It is a strongly typed view of type NewsEditViewData.
When the view loads, it gets a news item's data by ID from the news service. So in my test I created a stub of the news service:
var id = 1;
var news = new News();
newsServiceStub
.Stub(x => x.FindById(id))
.Return(news);
Now I need to map this news item to NewsEditViewData. I have a mapper (AutoMapper) that does this for me, and in my test I did the following:
newsMapperStub
.Stub(x => x.Map(news, typeof(News), typeof(NewsEditViewData)))
.Return(newsEditViewData);
I'm not sure if I am on the right track so far?
Then I have the following piece of code:
// Act
var actual = sut.Edit(id);
Don't work from my code, I want an answer following best practices. So what all do I need to check for in my assert part? Do I need to also check that a record was returned? I was thinking in the lines of something like:
actual
.AssertViewRendered()
.WithViewData<NewsEditViewData>()
.ShouldBe(newsEditViewData);
This fails. Can someone please help me rewrite this test so that it passes. I want it to check all that needs to be checked.
Here is the full test:
[Test]
public void Edit_should_render_Edit_view()
{
// Arrange
var id = 1;
var news = new News();
var newsEditViewData = new NewsEditViewData();
newsServiceStub
.Stub(x => x.FindById(id))
.Return(news);
newsMapperStub
.Stub(x => x.Map(news, typeof(News), typeof(NewsEditViewData)))
.Return(newsEditViewData);
// Act
var actual = sut.Edit(id);
// Assert
actual
.AssertViewRendered()
.WithViewData<NewsEditViewData>()
.ShouldBe(newsEditViewData);
}
UPDATE 2011-02-14:
In my NewsController I have the following:
private INewsService newsService;
private IMapper newsMapper;
public NewsController(INewsService newsService)
{
Check.Argument.IsNotNull(newsService, "newsService");
this.newsService = newsService;
newsMapper = new NewsMapper(); // TODO: Use dependency injection
}
The action method looks like this:
public ActionResult Edit(int id)
{
Check.Argument.IsNotZeroOrNegative(id, "id");
var news = newsService.FindById(id);
var newsEditViewData = (NewsEditViewData)newsMapper.Map(news, typeof(News), typeof(NewsEditViewData));
return View(newsEditViewData);
}
The error that I am getting in NUnit is:
MyProject.Web.UnitTests.Controllers.NewsControllerTests.Edit_RenderView_EditView:
MvcContrib.TestHelper.AssertionException : was MyProject.Web.Common.ViewData.NewsEditViewData but expected MyProject.Web.Common.ViewData.NewsEditViewData
You haven't shown none of your controller, repository, models. It's a question that is close to impossible to answer without this information. So lets start guessing. You have a model and a view model:
public class News { }
public class NewsEditViewData { }
I am leaving them without any properties for the purpose of this post. Then you probably have a service which is responsible for retrieving and saving your model (the view model should never appear as in/out argument of your service layer). The service should never know about the view model:
public interface INewsService
{
News FindById(int id);
void CreateNews(News news);
}
Then you probably have a mapper:
public interface IMapper
{
object Map(object source, Type sourceType, Type destinationType);
}
And finally I suppose that you have a controller that you are trying to test:
public class NewsController : Controller
{
private readonly INewsService _newsService;
private readonly IMapper _newsMapper;
public NewsController(INewsService newsService, IMapper newsMapper)
{
_newsService = newsService;
_newsMapper = newsMapper;
}
public ActionResult Edit(int id)
{
// WARNING: Meaningless action ahead as it retrieves some
// model from the service and passes this model to
// the service back again for update. In the meantime
// the model is converted to a view model using a mapper
// and passed to the view. So totally meaningless in a real
// application but let's consider for the purpose of this demonstration
var news = _newsService.FindById(id);
_newsService.CreateNews(news);
var newsEditViewData = (NewsEditViewData)_newsMapper.Map(news, typeof(News), typeof(NewsEditViewData));
return View(newsEditViewData);
}
}
OK, up until here it is you that should have provided this information.
And now I can start answering your question about the unit test which might look like this:
[Test]
public void Edit_should_fetch_news_model_from_service_given_an_id_parameter_create_news_and_pass_a_viewmodel_to_the_view()
{
// arrange
// TODO : move this part in the initialization section
// of your unit test to avoid repeating it on each method
var newsServiceStub = MockRepository.GenerateStub<INewsService>();
var newsMapperStub = MockRepository.GenerateStub<IMapper>();
var sut = new NewsController(newsServiceStub, newsMapperStub);
new TestControllerBuilder().InitializeController(sut);
var news = new News();
var id = 123;
var newsEditViewData = new NewsEditViewData();
newsServiceStub
.Stub(x => x.FindById(id))
.Return(news);
newsMapperStub
.Stub(x => x.Map(news, typeof(News), typeof(NewsEditViewData)))
.Return(newsEditViewData);
// act
var actual = sut.Edit(id);
// assert
actual
.AssertViewRendered()
.WithViewData<NewsEditViewData>()
.ShouldBe(newsEditViewData);
newsServiceStub.AssertWasCalled(x => x.CreateNews(news));
}
Related
I'm just learning how dependency injection and mocking work, but I'd like some feedback on how I'm setting up a couple of tests. I can get them to pass, but I'm not sure this is all I need.
This is an MVC application that makes Web API calls to return data. For this example I'm running queries in the Web APIs that populate dropdowns.
Please give me any and all suggestions about what I'm doing right or wrong here or anything I should be doing differently.
Setup file for Dependency Injection - Unity.WebAPI (NuGet Package)
UnityConfig.cs
public static class UnityConfig
{
public static void RegisterComponents()
{
var container = new UnityContainer();
// register all your components with the container here
// it is NOT necessary to register your controllers
// e.g. container.RegisterType<ITestService, TestService>();
container.RegisterType<IDropDownDataRepository, DropDownDataRepository>();
GlobalConfiguration.Configuration.DependencyResolver = new UnityDependencyResolver(container);
}
}
CONTROLLER
public class DropDownDataController : ApiController
{
private IDropDownDataRepository _dropDownDataRepository;
//Dependency Injection (I'm using Unity.WebAPI)
public DropDownDataController(IDropDownDataRepository dropDownDataRepository)
{
_dropDownDataRepository = dropDownDataRepository;
}
[HttpGet]
public HttpResponseMessage DateList()
{
try
{
return _dropDownDataRepository.DateList();
}
catch
{
throw new HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));
}
}
}
REPOSITORY
public class DropDownDataRepository : IDropDownDataRepository
{
//Is this fine in here, or should it be injected somehow too?
private MyDatabaseEntities db = new MyDatabaseEntities();
public HttpResponseMessage DateList()
{
var sourceQuery = (from p in db.MyProcedure()
select p).ToList();
string result = JsonConvert.SerializeObject(sourceQuery);
var response = new HttpResponseMessage();
response.Content = new StringContent(result, System.Text.Encoding.Unicode, "application/json");
return response;
}
}
INTERFACE
public interface IDropDownDataRepository
{
HttpResponseMessage DateList();
}
UNIT TESTS
/// <summary>
/// Tests the DateList method is run
/// I pieced this kind of test together from examples online
/// I'm assuming this is good for a simple test
/// </summary>
[TestMethod]
public void DateListTest1()
{
//Arrange
var mockRepository = new Mock<IDropDownDataRepository>();
mockRepository.Setup(x => x.DateList());
var controller = new DropDownDataController(mockRepository.Object);
//Act
controller.DateList();
//Assert
mockRepository.VerifyAll();
}
/// <summary>
/// Tests the DateList method returns correct status code.
/// This will run with success, but I'm not sure if that's just
/// because I'm telling it to return what I'm expecting.
/// I welcome suggestions for improvement.
/// </summary>
[TestMethod]
public void DateListTest2()
{
//Arrange
var mockRepository = new Mock<IDropDownDataRepository>();
mockRepository
.Setup(x => x.DateList())
//This will only succeed if I have the Returns property here,
//but isn't that just bypassing the actual "test" of whether or
//not this works?
.Returns(new HttpResponseMessage(HttpStatusCode.OK));
DropDownDataController controller = new DropDownDataController(mockRepository.Object);
controller.Request = new HttpRequestMessage();
controller.Configuration = new HttpConfiguration();
//Act
var response = controller.DateList();
//Assert
Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
}
UPDATE 1
One of my main questions here is what the .Returns property actually does. In my second unit test, I'm telling it to return OK, then check if it returns OK. I can't see how that's actually testing anything.
One of my main questions here is what the .Returns property actually
does. In my second unit test, I'm telling it to return OK, then check
if it returns OK. I can't see how that's actually testing anything.
The code:
mockRepository
.Setup(x => x.DateList())
//This will only succeed if I have the Returns property here,
//but isn't that just bypassing the actual "test" of whether or
//not this works?
.Returns(new HttpResponseMessage(HttpStatusCode.OK));
Says that when the mockRepository recieves a call to DateList() then it should return a new HttpResponseMessage(HttpStatusCode.OK).
So inside
[HttpGet]
public HttpResponseMessage DateList()
when the unit test reaches the line
return _dropDownDataRepository.DateList();
The mocked object fires and returns new HttpResponseMessage(HttpStatusCode.OK)
A better name for this test would be instead of DateListTest2 something like DateList_Returns_Status_Code_From_Repository as that is what you're arranging in the test.
To be honest controller.DateList() doesn't have much logic so that's about the only golden path test you could have.
I'm building a website in MVC 4 & using Automapper to map from domain objects to Viewmodel objects. I have injected Automapper as stated here http://rical.blogspot.in/2012/06/mocking-automapper-in-unit-testing.html
and it's working fine inside action methods while debugging, but during unit testing the action method when I inject automapper service I find that service.map is returning null. But while debugging the mapping is fine. I'm not being able to find the reason, trying for over 4 hrs. I have a domain class called Interview & its corrosponding viewmodel as InterviewModel. I have initialized mapping as CreateMap(); in automapper profile config, that has been called from global startup method. Below is the controller & action...
public class NewsAndViewsController : Controller
{
private IInterviewRepository repository;
private IMappingService mappingService;
public NewsAndViewsController(IInterviewRepository productRepository, IMappingService autoMapperMappingService)
{
repository = productRepository;
mappingService = autoMapperMappingService;
}
[HttpPost, ValidateAntiForgeryToken]
[UserId]
public ActionResult Edit(InterviewModel interView, string userId)
{
if (ModelState.IsValid)
{
var interView1 = mappingService.Map<InterviewModel, Interview>(interView);
**// THE ABOVE LINE RETURNING NULL WHILE RUNNING THE BELOW TEST, BUT NOT DURING DEBUGGING**
repository.SaveInterview(interView1);
TempData["message"] = string.Format("{0} has been saved", interView.Interviewee);
return RedirectToAction("Create");
}
return View(interView);
}
}
[TestMethod]
public void AddInterview()
{
// Arrange
var interviewRepository = new Mock<IInterviewRepository>();
var mappingService = new Mock<IMappingService>();
var im = new InterviewModel { Interviewee="sanjay", Interviewer="sanjay", Content="abc" };
mappingService.Setup(m => m.Map<Interview, InterviewModel>(It.IsAny<Interview>())).Returns(im);
var controller = new NewsAndViewsController(interviewRepository.Object, mappingService.Object);
// Act
var result = controller.Edit(im, "2") as ViewResult;
// Assert - check the method result type
Assert.IsNotInstanceOfType(result, typeof(ViewResult));
}
In your test you've got your Interview and InterviewModel classes crossed up in the mappingService.Setup() call (as an aside, I think you could use better naming conventions, or don't use var, to keep your objects clear - "im", "interview" and "interview1" don't make it easy to follow which is the model and which is the view object).
Try this:
[TestMethod]
public void AddInterview()
{
// Arrange
var interviewRepository = new Mock<IInterviewRepository>();
var mappingService = new Mock<IMappingService>();
var interview = new Interview();
var im = new InterviewModel { Interviewee="sanjay", Interviewer="sanjay", Content="abc" };
mappingService.Setup(m => m.Map<InterviewModel, Interview>(im).Returns(interview);
var controller = new NewsAndViewsController(interviewRepository.Object, mappingService.Object);
// Act
var result = controller.Edit(im, "2") as ViewResult;
// Assert - check the method result type
Assert.IsNotInstanceOfType(result, typeof(ViewResult));
}
I am new to nSubstitute. And I am writing test method for my controller class. I have a TestMethod called GetDefaultStateTest() which having Substitute class as shown below
[TestMethod]
public void GetDefaultStateTest()
{
var _GetDefaultState = Substitute.For<CustomerController>(ICustomer cus);
Assert.IsNotNull(_GetDefaultState.GetDefaultState());
}
Because my controller class having parameterized constructor as below.
public class CustomerController : Controller
{
private readonly ICustomer _customer;
public CustomerController(ICustomer customer)
{
_customer = customer;
}
public string GetDefaultState()
{
// Get default state from settings table
List<tblSettings> settings = new List<tblSettings>();
// Calling service method GetSettings
settings = _customer.GetSettings();
var defaultState = from setting in settings
where setting.Desc == "DefaultState"
select setting.Settings;
string strState = "";
foreach (var oState in defaultState)
{
strState = oState;
break;
}
return strState;
}
}
While run the test method, it raise null reference issue. Because of parameter ICustomer is null
var _GetDefaultState = Substitute.For<CustomerController>(ICustomer cus);
How to resolve this problem.
If you are testing your controller class then you do not want to substitute for it, you want to use a real one (otherwise you'd just be testing a fake object "works" :)). Where you may want to substitute is for that class's dependencies, in this case, ICustomer.
[TestMethod]
public void GetDefaultStateTest()
{
var customer = Substitute.For<ICustomer>();
var controller = new CustomerController(customer);
Assert.IsNotNull(controller.GetDefaultState());
}
You may then want to fake out the ICustomer.GetSettings() method so you can test what your controller does with that data:
[TestMethod]
public void GetDefaultStateTestFromSettings()
{
var customer = Substitute.For<ICustomer>();
customer.GetSettings().Returns(somethingSensible);
var controller = new CustomerController(customer);
Assert.AreEqual(expectedDefaultState, controller.GetDefaultState());
}
As an aside, sometimes it makes more sense to use real objects (say, a real implementation of ICustomer) rather than substitutes. This will depend on how well-defined the interactions with the dependencies are, where you want to define the boundaries of your system under test, and how much confidence the test gives you that the system under test is working correctly. Or put more simply, whatever makes it easy and reliable to test. :)
Hope this helps.
I'm starting with unit testing in the asp.net mvc 4 framework.
I got a repository with basic crud methods and a save method. When I create a unit test I create a test repository and test if e.g. a item to the collection is added. That all goes smoothly but I cannot test if the save method is hit.
I tried to add a boolean property to the test repository which will be set to true if .save() is hit. But then I need to change the interface, and also the database repository. Which is in my opinion neither practical nor best practice.
What is the best method to test this? Thank you in advance for your answer.
My code:
the fake repository:
public class TestUserRepository : IUserManagementRepository
{
/// <summary>
/// entries used used for testing
/// </summary>
private List<User> _entities;
/// <summary>
/// constructor
/// </summary>
public TestUserRepository()
{
_entities = new List<User>();
_entities.Add(new User
{
Id = 1,
InsertDate = DateTime.Now,
LastUpdate = DateTime.Now,
Username = "TestUserName",
Password = "TestPassword"
});
}
...
public void Create(User task)
{
_entities.Add(task);
}
public void Save()
{
//do nothing
}
}
the controller to test:
[HttpPost]
public ActionResult Create(User user)
{
if (ModelState.IsValid)
{
_repository.Create(user);
_repository.Save();
return RedirectToAction("Index");
}
else
{
return View(user);
}
}
and the test
[TestMethod()]
public void CreateTest()
{
IUserManagementRepository repository = new TestUserRepository();
UserController controller = new UserController(repository);
User user = new User { Username = "UnitTestUserName", InsertDate = DateTime.Now, LastUpdate = DateTime.Now, Password = "Password" };
ActionResult actionResult = controller.Create(user);
User returnedUser = repository.FindBy(u => u.Username == "UnitTestUserName").First<User>();
Assert.IsNotNull(actionResult);
Assert.AreEqual(user, returnedUser);
}
You must be careful not to write a bunch of unit tests that just test your test repository.
Consider the following scenario:
You have a service method, that is supposed to add an item to your repository.
Your unit test calls this method, and you should verify that the appropriate "AddX" method was called on the repository.
This is a valid unit test scenario, to test it you can use your test repository. Since it is your test object, you have full control over it. You can expose properties such as "AddXMethodCallCount" or something similar.
Over time you will find yourself writing a lot of test code that is pretty much boilerplate. The alternative, which I strongly recommend, is to use a mocking framework:
https://stackoverflow.com/questions/37359/what-c-sharp-mocking-framework-to-use
It takes some getting used to, but once you get it, it will speed up your unit testing significantly.
If you don't want to use mocking yet, but want to still achieve your goal of verifying whether or not Save() is called, I would suggest just adding a publicly exposed SaveMethodCallCount property:
public class TestUserRepository : IUserManagementRepository
{
...
public SaveMethodCallCount {get; set;}
...
public void Save()
{
SaveMethodCallCount++;
}
}
This works, because in your unit test you can actually say:
TestUserRepository repository = new TestUserRepository();
The UserController does not care, as long as the passed in parameter implements the IUserManagementRepository interface. The controller interacts with the repository object through the interface, but the unit test does not have to, and the TestUserRepository, being a test class, is allowed to have much more functionality, that does not have to be exposed through the interface.
So your test could look something like:
[TestMethod()]
public void CreateTest()
{
TestUserRepository repository = new TestUserRepository();
UserController controller = new UserController(repository);
User user = new User { Username = "UnitTestUserName", InsertDate = DateTime.Now, LastUpdate = DateTime.Now, Password = "Password" };
ActionResult actionResult = controller.Create(user);
User returnedUser = repository.FindBy(u => u.Username == "UnitTestUserName").First<User>();
Assert.IsNotNull(actionResult);
Assert.AreEqual(user, returnedUser);
Assert.AreEqual(1, repository.SaveMethodCallCount);
}
To make my example complete, let me show you what this would look like if you used a mocking framework, like Moq. You can see some more examples here. The example test method uses Moq and Arrange/Act/Assert, and tests only one thing - that Save() is called when Create() is called.
[TestMethod()]
public void Test_SaveCalledWhenCreateCalled()
{
// Arrange
// First, instead of creating an instance of your test class, you create a mock repository.
// In fact, you don't need to write any code, the mocking framework handles it.
var mockRepository = new Mock<IUserManagementRepository>();
// and pass the mock repository (which implements the IUserManagementRepository) to your controller
UserController controller = new UserController(mockRepository);
// Act
ActionResult actionResult = controller.Create(user);
// Assert
// see how easy it is to do with a mocking framework:
mockRepository.Verify(rep => rep.Save(), Times.AtLeastOnce());
}
I have the following controller action:
public ActionResult Edit(int id)
{
var news = newsRepository.GetNewsByID(id);
Mapper.CreateMap<News, NewsEditModel>();
var newsEditModel =
(NewsEditModel)Mapper.Map(news, typeof(News), typeof(NewsEditModel));
return View(newsEditModel);
}
And the corresponding test:
[Test]
public void Edit_should_render_view()
{
// Arrange
var id = 1;
var newsEditModel = new NewsEditModel();
// Act
var actual = sut.Edit(id);
// Assert
actual
.AssertViewRendered()
.WithViewData<NewsEditModel>()
.ShouldBe(newsEditModel);
}
In the NUnit GUI I get the following error:
MyProject.Web.UnitTests.Controllers.NewsControllerTests.Edit_should_render_view:
MvcContrib.TestHelper.AssertionException : was MyProject.Web.Common.ViewData.NewsEditModel but expected MyProject.Web.Common.ViewData.NewsEditModel
I don't know how to write the corresponding unit test. Can someone please help me?
Your test is comparing two different instances of NewsEditModel - one instance that you create in your test code, and the other that is created in the action method.
If you want to examine the model property values as part of your test, you could do this:
var model = actual
.AssertViewRendered()
.WithViewData<NewsEditModel>();
// Check that model is not null
Assert.That(model, Is.Not.Null);
// Check that model ID is same as passed into action method
Assert.That(model.Id, Is.EqualTo(1));
// or alternatively ...
model.Id.ShouldBe(1);