简体   繁体   中英

Unit Test a method that is dependent on other public method

I get very confused when I have to unit test a method which is calling multiple public methods of other classes. Here is the example

using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using SkillKindle.BLL;
using SkillKindle.BLL.ClassDetails;
using SkillKindle.BLL.SkClasses;
using SkillKindle.Domain.Models.SkClasses;
using SkillKindle.Infrastructure;
using SkillKindle.Web.Core.Infrastructure.ErrorHandling;
using SkillKindleWeb.Mappers;
using SkillKindleWeb.ViewModels.ClassDetails;

namespace SkillKindleWeb.Controllers
{
    [CustomHandleError(ExceptionType = typeof (BusinessValidationException))]
    public class ClassDetailsController : BaseController
    {
        private readonly ILogger _logger;
        private readonly IMapperService _mapperService;
        private readonly IAccessorFactory _accessorFactory;
        private const int RegistrationId = 34;

        private IClassDetailsAccessor ClassDetailsAccessor
        {
            get { return _accessorFactory.CreateClassDetailsAccessor(); }
        }

        private ISkClassAccessor SkClassAccessor
        {
            get { return _accessorFactory.CreateSkClassAccessor(); }
        }

        private IClassCreativeAccessor ClassCreativeAccessor
        {
            get { return _accessorFactory.CreateClassCreativeAccessor(); }
        }

        public ClassDetailsController(ILogger logger, IMapperService mapperService,
                                      IAccessorFactory accessorFactory)
        {
            _logger = logger;
            _mapperService = mapperService;
            _accessorFactory = accessorFactory;
        }

        public ViewResult Index(int classCreativeId)
        {
            var classCreative = ClassCreativeAccessor.GetClassCreative(classCreativeId);
            if (classCreative == null)
            {
                throw new HttpException(404, "The url is not valid");
            }

            var batches = ClassCreativeAccessor.GetFutureBatches(classCreativeId);
            IList<ClassTicket> tickets = new List<ClassTicket>();
            IList<Venue> venues = new List<Venue>();

            if (batches.Count > 0)
            {
                tickets =
                    ClassCreativeAccessor.GetTickets(
                        batches.Select(batch => batch.ClassScheduleId).Distinct().ToArray());
                venues = SkClassAccessor.GetVenues(batches.Select(batch => batch.VenueId).Distinct().ToArray());
            }

            var classDetailsViewModel = _mapperService.ClassCreativeToClassDetailsViewModel(classCreative);
            var batchViewModels = _mapperService.BatchToClassDetailsBatchViewModel(batches).ToList();
            var ticketViewModels = _mapperService.ClassTicketToClassDetailsTicketViewModel(tickets).ToList();
            var venueViewModels = _mapperService.VenueToClassDetailsVenueViewModel(venues).ToList();

            var indexViewModel = new IndexViewModel()
                {
                    Batches = batchViewModels,
                    Tickets = ticketViewModels,
                    ClassDetails = classDetailsViewModel,
                    Venues = venueViewModels
                };
            return View(indexViewModel);
        }
    }
}

Here Index method is dependent on mapperService, SkClassAccessor, ClassDetailsAccessor, ClassCreativeAccessor public methods. I have unit tested those public method separately. Now when it comes to test Index method, I need to check the correctness of indexViewModel. Here are couple of options with me.

Option 1. Mock the public methods of dependent classes to return fake objects and check IndexViewModel has those fake object. I am not sure if this is a real test. Also it does not test that I am passing the write arguments to these mock public methods.

Option 2. Don't mock the public methods of dependent classes but fake the dependencies of dependent classes. eg Fake the list of tickets ClassCreativeAccessor.GetTickets would operate on. This approach would verify that I passing the right argument to dependent public methods. But here I would be testing public methods again

I am not sure which approach is correct. Appreciate you help.

I am not sure if this is a real test.

This is a unit test as it should be. Don't mix it up with integration test.

Also it does not test that I am passing the write arguments to these mock public methods.

When you are mocking dependencies (first option) you always can verify that methods was called with appropriate parameters. Eg with Moq:

mock.Verify(foo => foo.Execute("ping"));

will check if method Execute of dependency foo was called with parameter "ping" . Same way you can verify your ClassCreativeAccessor was called with appropriate parameters:

int classCreativeId = 42;
List<Batch> batches = new List<Batch>();

creativeAccessorMock.Setup(ca => ca.GetFutureBatches(classCreativeId))
                    .Returns(batches);
...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM