依赖于其他公共方法的方法如何进行单元测试

3

当我需要对调用其他类的多个公共方法的方法进行单元测试时,我会感到非常困惑。以下是一个例子:

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);
        }
    }
}

这里的Index方法依赖于mapperService、SkClassAccessor、ClassDetailsAccessor和ClassCreativeAccessor的公共方法。我已经单独对这些公共方法进行了单元测试。现在,当测试Index方法时,我需要检查indexViewModel的正确性。以下是我手头的几个选项。
选项1:模拟依赖类的公共方法以返回虚假对象,并检查IndexViewModel是否具有这些虚假对象。我不确定这是否是一个真正的测试。而且它并没有测试我是否将正确的参数传递给这些模拟的公共方法。
选项2:不要模拟依赖类的公共方法,而是伪造依赖类的依赖关系。例如,伪造票据列表ClassCreativeAccessor.GetTickets将操作。这种方法将验证我是否将正确的参数传递给依赖的公共方法。但这里我将再次测试公共方法。
我不确定哪种方法是正确的。感谢您的帮助。

我认为你应该采用第一种方法,因为重新测试所有的方法是没有意义的。如果你改变了函数的功能,那么你就必须修复多个单元测试,这不是最佳实践。 - rajansoft1
1个回答

2

我不确定这是否是一项真正的测试。

这是一个良好的单元测试,不要与集成测试混淆。

此外,它没有测试我是否向这些模拟公共方法传递了正确的参数。

当你在mock依赖项时(第一种选择),你总是可以验证方法是否被调用并且传递了适当的参数。例如,使用 Moq:

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

将检查依赖项foo的方法Execute是否使用参数"ping"被调用。同样,您可以验证ClassCreativeAccessor是否按适当的参数被调用:

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

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

2
我想你是对的。我已经按照你的建议编写了单元测试。非常感谢你。 - Amit Kumar

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接