使用 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);
我正在实施单元测试以测试助手中的方法 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);