Problems in creating unit test for ASP .NET MVC

前端 未结 1 1935
日久生厌
日久生厌 2020-12-12 02:55

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]
[         


        
相关标签:
1条回答
  • 2020-12-12 03:15

    Problem 1

    Automapper has both a Static and Instance API. You should consider using the instance API with IMapper and inject that into your controller.

    public class PublisherController : Controller {
        private readonly IMapper mapper;
    
        public PublisherController(IJournalRepository journalRepository, IMembershipRepositry membershipRepository, IMapper mapper) {
            //...other code omitted for brevity
            this.mapper = mapper;
        }
    
        //...other code omitted for brevity
    
        [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");
        }
    }
    

    That would allow for better mocking/faking/configuration of the mapping as needed. You should make sure to configure IMapper for dependency injection into your controllers.

    if you are unable to change to the instance api then you need to make sure that the mapper is Initialize before running the tests

    Mapper.Initialize(cfg => {
        cgf.CreateMap<JournalViewModel, Journal>();
    });
    

    Problem 2

    your arrangement in the test is

    Mock.Arrange(() => journalRepository.DeleteJournal(null)).Returns(new OperationStatus
    {
        Status = true
    });
    

    This as you realized wont work for cases where you call journalRepository.DeleteJournal with an actual instance. Assuming that you are using JustMock from Telerik you should arrange for a more flexible argument.

    Mock.Arrange(() => journalRepository.DeleteJournal(Arg.IsAny<Journal>())).Returns(new OperationStatus
    {
        Status = true
    });
    

    Source : Handling Arguments in JustMock Arrangements

    Complete Test: Instance API

    [TestMethod]
    public void Delete_Journal() {
        // Arrange
    
        //Configure mapping just for this test but something like this
        //should be in accessible from your composition root and called here.
        var config = new MapperConfiguration(cfg => {
            cfg.CreateMap<Journal, JournalViewModel>();
            cfg.CreateMap<JournalViewModel, Journal>();
        });
    
        var mapper = config.CreateMapper(); // IMapper
    
        // Simulate PDF file
        var mockFile = Mock.Create<HttpPostedFileBase>();
        Mock.Arrange(() => mockFile.FileName).Returns("Test.pdf");
        Mock.Arrange(() => mockFile.ContentLength).Returns(255);
    
        // Create view model to send.
        var 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
    
        var status = new OperationStatus {
            Status = true
        };
    
        Mock.Arrange(() => journalRepository.DeleteJournal(Arg.IsAny<Journal>())).Returns(status);
    
        var controller = new PublisherController(journalRepository, membershipRepository, mapper);
    
        // Act        
        var result = controller.Delete(journalViewModel) as RedirectToRouteResult;
    
        // Assert
        Assert.AreEqual(result.RouteValues["Action"], "Index");
    }
    

    Complete Test: Static API

    [TestMethod]
    public void Delete_Journal() {
        // Arrange
    
        //Configure mapping just for this test but something like this
        //should be in accessible from your composition root and called here.
        Mapper.Initialize(cfg => {
            cfg.CreateMap<Journal, JournalViewModel>();
            cfg.CreateMap<JournalViewModel, Journal>();
        });
    
        // Simulate PDF file
        var mockFile = Mock.Create<HttpPostedFileBase>();
        Mock.Arrange(() => mockFile.FileName).Returns("Test.pdf");
        Mock.Arrange(() => mockFile.ContentLength).Returns(255);
    
        // Create view model to send.
        var 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
    
        var status = new OperationStatus {
            Status = true
        };
    
        Mock.Arrange(() => journalRepository.DeleteJournal(Arg.IsAny<Journal>())).Returns(status);
    
        var controller = new PublisherController(journalRepository, membershipRepository);
    
        // Act        
        var result = controller.Delete(journalViewModel) as RedirectToRouteResult;
    
        // Assert
        Assert.AreEqual(result.RouteValues["Action"], "Index");
    }
    
    0 讨论(0)
提交回复
热议问题