开发者

What's wrong with this TestMethod?

开发者 https://www.devze.com 2023-03-28 12:48 出处:网络
So I want to learn a little bit of TDD and wanted to see if I could test an Index action which should simply return a View.

So I want to learn a little bit of TDD and wanted to see if I could test an Index action which should simply return a View.

The test doesn't pass an开发者_JAVA百科d the error is

Test method Summumnet.Tests.Controllers.PhysicalTestsControllerTest.IndexShouldReturnView threw exception: System.ArgumentException: Expression is not a property access: c => c.FindById(1)

Here's my controller action code:

[Authorize]
    [AllowedToEditEHR]
    public class PhysicalTestsController : Controller
    {
        private IUnitOfWork unitOfWork;
        private IRepository<EHR> ehrRepository;
        private const int PAGESIZE = 5;


        public PhysicalTestsController(IUnitOfWork unit)
        {
            unitOfWork = unit;
            ehrRepository = unitOfWork.EHRs;

        }

        public ActionResult Index(int ehrId, int? page)
        {
            EHR ehr = ehrRepository.FindById(ehrId);
            var physicaltests = ehr.PhysicalTests.Where(test => !test.IsDeleted).OrderByDescending(test => test.CreationDate);
            List<PhysicalTestListItem> physicalTestsVM = new List<PhysicalTestListItem>();
            Mapper.Map(physicaltests, physicalTestsVM);
            var paginatedTests = physicalTestsVM.ToPagedList(page ?? 0, PAGESIZE);
            return View(paginatedTests);
        }

and here's the test

[TestClass]
    public class PhysicalTestsControllerTest
    {
        [TestMethod]
        public void IndexShouldReturnView()
        {
            // Arrange

            var mock = new Mock<ControllerContext>();
            mock.SetupGet(p => p.HttpContext.User.Identity.Name).Returns("nacho");
            mock.SetupGet(p => p.HttpContext.Request.IsAuthenticated).Returns(true);

            var mockUnitofWork = new Mock<IUnitOfWork>();
            var mockEhrRepository = new Mock<IRepository<EHR>>();
            mockEhrRepository.SetupGet(c => c.FindById(1)).Returns(new EHR { PhysicalTests = new List<PhysicalTest>()});
            mockUnitofWork.SetupGet(p=>p.EHRs).Returns(mockEhrRepository.Object);
            PhysicalTestsController controller = new PhysicalTestsController(mockUnitofWork.Object);
            controller.ControllerContext = mock.Object;

            // Act
            ViewResult result = controller.Index(1, 0) as ViewResult;

            // Assert
            Assert.IsNotNull(result);
        }


A few pointers:

  1. You don't need to mock HttpContext for this test. Sure, you have an Authorize attribute on your controller, but action filters aren't run when you're unit testing your controllers. So you can just assume that the user will be authenticated and authorized.

  2. SetupGet is, I believe, pretty obsolete. You should consider using Setup instead:

    mockUnitofWork.Setup(p => p.EHRs).Returns(mockEhrRepository.Object);
    

    THis is in fact what is causing your error, since SetupGet can only be used on properties, while Setup can be used on more or less anything. Since FindById isn't a property (it's a method), you get that error.

  3. When setting up a function call, you usually get better results if you don't give exact input arguments, but rather specify conditions that the input arguments must satisfy. This avoids unexpected and often hard-to-track testing bugs when you pass in two identical - but separate - instances of a class, and expect them to be the same.

    In Moq, you can use the static methods on It to do this. If you want to allow for any int, just say It.IsAny<int>() in place of the integer argument. If you want to be specific, you can use a lambda expression to declare when the behavior should apply, using It.Is<int>(i => someCondition(i)). So instead of .Setup(c => c.FindById(1)) you say

    mockEhrRepository.Setup(r => r.FindById(It.Is<int>(i => i == 1)).Returns(...)
    

    For value types this doesn't make any difference, but I think it's a good habit. I usually choose to not care which integer is given, which simplifies the setup expression a little:

    mockEhrRepository.Setup(r => r.FindById(It.IsAny<int>()).Returns(...)
    

But to be clear: The only thing in this post you need to do to get rid of your error, is to change SetupGet to Setup.

0

精彩评论

暂无评论...
验证码 换一张
取 消