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: \Source\Journals.Web.Tests\Controllers\PublisherControllerTest.cs : line 132
Test Outcome: Failed Test Duration: 0:00:00,3822468Result StackTrace: at Journals.Web.Controllers.PublisherController.Delete(JournalViewModel journal) in \Source\Journals.Web\Controllers\PublisherController.cs:line 81 at Journals.Web.Tests.Controllers.PublisherControllerTest.Delete_Journal() in \Source\Journals.Web.Tests\Controllers\PublisherControllerTest.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.
TestBase
class where you call your mapping configuration code. The staticMapper
in your test doesn't know anything about the mapping configuration from yourGlobal.asax.cs
. – TillfordIMapper
) instead of static API as you have already discovered the difficulties in unit testing static APIs – Excogitate