使用 Repository 接口模拟 UnitOfWork 接口 属性

Mock UnitOfWork interface with a Repository interface property

我正在实施单元测试以测试助手中的方法 class。
我已经模拟了我的 IRepository 接口并将它的对象传递给我模拟的 IUnitOfWork,因为这个 IRepository 接口是 UnitOfWork 的 属性。在调试单元测试时,我发现 helper class 中对 '_unitOfWork.Booking.OverlappingBooking' 的调用总是 return 为空。 OverlappingBooking() 根本不会被调用。

public class BookingHelper
    {
        private IUnitOfWork _unitOfWork;

        public BookingHelper(IUnitOfWork unitOfWork)
        {
            _unitOfWork = unitOfWork;
        }

        public string OverlappingBookingsExist(Booking booking)
        {
            if (booking.Status == "Cancelled")
                return string.Empty;

            var bookings = _unitOfWork.Booking.GetActiveBookings<Booking>().Where(
                        b => b.Id != booking.Id && b.Status != "Cancelled"); 

            var overlappingBooking = _unitOfWork.Booking.OverlappingBooking(bookings, booking);


            return overlappingBooking;
        }
    }

我的工作单位

 public interface IUnitOfWork
    {
        IBookingHelperRepository Booking { get; set; }
    }
    public class UnitOfWork: IUnitOfWork
    {

        public IBookingHelperRepository Booking { get; set; }

        public UnitOfWork()
        {
            Booking = new BookingHelperRepository();
        }

    }

存储库

public interface IBookingHelperRepository
    {
        IQueryable<T> GetActiveBookings<T>();

        string OverlappingBooking(IQueryable<Booking> bookings, Booking booking);
    }


    public class BookingHelperRepository: IBookingHelperRepository
    {
        public IQueryable<T> GetActiveBookings<T>()
        {
            var resp = new List<T>().AsQueryable();

            return resp;
        }

        public string OverlappingBooking(IQueryable<Booking> bookings, Booking booking)
        {
          var overlappingBooking =  bookings.FirstOrDefault(
                    b => booking.ArrivalDate >= b.ArrivalDate
                        && booking.ArrivalDate < b.DepartureDate
                        || booking.DepartureDate > b.ArrivalDate
                        && booking.DepartureDate <= b.DepartureDate);

            return overlappingBooking == null ? string.Empty : overlappingBooking.Reference;
        }
    }

我已按如下方式设置我的测试 class。

 [TestClass]
    public class BookingHelperTests
    {
 private Mock<IBookingHelperRepository> bookingHelperRepository;
 private BookingHelper bookingHelper;
 private Booking booking;
 private Mock<IUnitOfWork> unitOfWork;
 [TestInitialize]
        public void Initialise()
        {
            unitOfWork = new Mock<IUnitOfWork>();
            bookingHelper = new BookingHelper(unitOfWork.Object);
            bookingHelperRepository = new Mock<IBookingHelperRepository>();
            .....
        }

 [TestMethod]
        public void OverlappingBookingsExist_BookingStartsAndFinishesBeforeAnExistingBooking_ShouldReturnEmptyString()
        {
            bookingHelperRepository.Setup(y => y.GetActiveBookings<Booking>()).Returns(bookingListBefore.AsQueryable());
            unitOfWork.Setup(x => x.Booking).Returns(bookingHelperRepository.Object);

            //Act
            var result = bookingHelper.OverlappingBookingsExist(booking);

            //Assert
            Assert.AreEqual("", result);
        }

您要测试的代码调用了您不模拟的 (IBookingHelperRepository)(IUnitOfWork.Booking).OverlappingBooking()。因为默认情况下模拟是松散的,所以它们 return null 而不是抛出异常。

如果您使用 MockBehavior.Strict 设置 new Mock<IBookingHelperRepository>(),您会收到一个异常,告诉您您尚未设置方法 string OverlappingBooking(IQueryable<Booking> bookings, Booking booking)

为了这样做:

var queryableBookings = bookingListBefore.AsQueryable();
bookingHelperRepository.Setup(y => y.GetActiveBookings<Booking>()).Returns(queryableBookings);
bookingHelperRepository.Setup(y => y.OverlappingBooking(queryableBookings, booking).Returns(booking.Reference);