I am creating some unit tests for my ASP .NET MVC Controller class and I ran into some very strange errors:
My controller code is below:
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Delete(JournalViewModel journal)
{
var selectedJournal = Mapper.Map<JournalViewModel, Journal>(journal);
var opStatus = _journalRepository.DeleteJournal(selectedJournal);
if (!opStatus.Status)
throw new System.Web.Http.HttpResponseException(new HttpResponseMessage(HttpStatusCode.NotFound));
return RedirectToAction("Index");
}
My test code is below:
[TestMethod]
public void Delete_Journal()
{
// Arrange
// Simulate PDF file
HttpPostedFileBase mockFile = Mock.Create<HttpPostedFileBase>();
Mock.Arrange(() => mockFile.FileName).Returns("Test.pdf");
Mock.Arrange(() => mockFile.ContentLength).Returns(255);
// Create view model to send.
JournalViewModel journalViewModel = new JournalViewModel();
journalViewModel.Id = 1;
journalViewModel.Title = "Test";
journalViewModel.Description = "TestDesc";
journalViewModel.FileName = "TestFilename.pdf";
journalViewModel.UserId = 1;
journalViewModel.File = mockFile; // Add simulated file
Mock.Arrange(() => journalRepository.DeleteJournal(null)).Returns(new OperationStatus
{
Status = true
});
// Act
PublisherController controller = new PublisherController(journalRepository, membershipRepository);
RedirectToRouteResult result = controller.Delete(journalViewModel) as RedirectToRouteResult;
// Assert
Assert.AreEqual(result.RouteValues["Action"], "Index");
}
Problem 1 - Mapping Exception:
Every time I run my test I receive the following exception:
Test Name: Delete_Journal Test
FullName: Journals.Web.Tests.Controllers.PublisherControllerTest.Delete_Journal
Test Source: SourceJournals.Web.TestsControllersPublisherControllerTest.cs
: line 132
Test Outcome: Failed Test Duration: 0:00:00,3822468
Result StackTrace: at
Journals.Web.Controllers.PublisherController.Delete(JournalViewModel
journal) in
SourceJournals.WebControllersPublisherController.cs:line 81 at
Journals.Web.Tests.Controllers.PublisherControllerTest.Delete_Journal()
in
SourceJournals.Web.TestsControllersPublisherControllerTest.cs:line
156 Result Message: Test method
Journals.Web.Tests.Controllers.PublisherControllerTest.Delete_Journal
threw exception: AutoMapper.AutoMapperMappingException: Missing type
map configuration or unsupported mapping.
Mapping types: JournalViewModel -> Journal
Journals.Model.JournalViewModel -> Journals.Model.Journal
Destination path: Journal
Source value: Journals.Model.JournalViewModel
It seems that there is a mapping problem between the classes JournalViewModel
and Journal
, however I don't know where that is. I added this code to the Application_Start
in Global.asax.cs
:
Mapper.CreateMap<Journal, JournalViewModel>();
Mapper.CreateMap<JournalViewModel, Journal>();
And mapping from Journal
to JournalViewModel
is working.
In the end I tried adding Mapper.CreateMap<JournalViewModel, Journal>();
as the first line of the Delete
method and then everything works, however I am not sure why.
Problem 2 - HTML Exception
Once the mapping is running with the workaround above, I have a problem in which the property Status
from var opStatus = _journalRepository.DeleteJournal(selectedJournal);
is always false, even though I used Mock to override it and make it always true. This causes the throwing of an HTML Exception that shouldn't happen.
EDIT
I changed in my Application_Start to:
Mapper.Initialize(cfg =>
{
cfg.CreateMap<Journal, JournalViewModel>();
cfg.CreateMap<JournalViewModel, Journal>();
});
But I still have the same error.
EDIT - Problem 2 Solved
It turns out that I forgot to add the mapping to my unit test class, so I did the following:
[TestInitialize]
public void TestSetup()
{
// Create necessary mappings
Mapper.CreateMap<Journal, JournalViewModel>();
Mapper.CreateMap<JournalViewModel, Journal>();
//...other code omitted for brevity
}
And it turns out that this was the source of the problem. I think that since the Global.asax.cs Application_Start() is never called in the unit tests, the Mapping is never created, so I had to do this myself in the unit tests initialization.
See Question&Answers more detail:
os