Search code examples
c#unit-testingmoqmstest

Mock UnitOfWork interface with a Repository interface property


I am implementing a unit test to test a method in a helper class.
I have mocked my IRepository interface and passed its object to my mocked IUnitOfWork because this IRepository interface is a property to the UnitOfWork. While debugging the unit test, I found out that the call to '_unitOfWork.Booking.OverlappingBooking' in the helper class always return null. The OverlappingBooking()is not invoked at all.

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

my UnitOfWork

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

        public IBookingHelperRepository Booking { get; set; }

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

    }

Repository

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

I have set up my test class as below.

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

Solution

  • The code you want to test calls (IBookingHelperRepository)(IUnitOfWork.Booking).OverlappingBooking(), which you don't mock. Because mocks are loose by default, they return null instead of throwing an exception.

    If you'd set up new Mock<IBookingHelperRepository>() with MockBehavior.Strict, you'd receive an exception telling you that you haven't set up the method string OverlappingBooking(IQueryable<Booking> bookings, Booking booking).

    In order to do so:

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