Nunit在存储库mock上设置虚拟属性

时间:2014-09-04 02:23:37

标签: c# unit-testing mocking nunit moq

我正在尝试测试使用以下域对象的方法。

public class PartyRoom
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Description { get; set; }
    public int Capacity { get; set; }
    public bool IsAvailable { get; set; }
    public virtual ICollection<RoomBooking> Bookings { get; set; }
}

public class RoomBooking
{
    public int Id { get; set; }
    public BookingType BookingType { get; set; }
    public int PartyRoomId { get; set; }
    public int TimeSlotId { get; set; }
    public DateTime Date { get; set; }
    public virtual PartyRoom PartyRoom { get; set; }
    public virtual TimeSlot TimeSlot { get; set; }
}

public enum BookingType
{
    PartyOrder,
    RoomRental,
    Corporate
}

我有一个存储库模拟我正在设置像这样的房间预订:

_roomBookingRepositoryMock.Setup(x => x.Get()).Returns(roomBookings.AsQueryable);

返回的roomBookings如下所示:

var roomBookings = new List<RoomBooking>
{
    new RoomBooking()
    {
        Id = 1,
        BookingType = BookingType.PartyOrder,
        Date = new DateTime(2014, 11, 15),
        PartyRoomId = 2,
        TimeSlotId = 1
    },
    new RoomBooking()
    {
        Id = 2,
        BookingType = BookingType.PartyOrder,
        Date = new DateTime(2014, 11, 15),
        PartyRoomId = 4,
        TimeSlotId = 3
    },
    new RoomBooking()
    {
        Id = 3,
        BookingType = BookingType.PartyOrder,
        Date = new DateTime(2014, 11, 15),
        PartyRoomId = 5,
        TimeSlotId = 4
    }
};

运行测试时发生的事情是public virtual ICollection<RoomBooking> Bookings { get; set; }始终为空。我不确定如何设置该属性,因为我的roombookings列表没有被嘲笑,因此SetupGet似乎不起作用?

当我运行测试时,我得到:

  

System.ArgumentNullException:值不能为空。

当单步执行时,该属性为null。我想我不能假设NUnit会像Entity Framework一样在代码中进行连接,但我很难知道如何访问它并设置属性。

*我尽可能多地发布了代码,由于项目原因我无法分享该方法,但我可以确认问题是该属性为null且未进行设置。

1 个答案:

答案 0 :(得分:0)

当您使用Entity Framework时,它会在内存中创建一个从数据库中检索到的信息的对象图。部分原因是它将使用虚拟属性为您提取其他表中的信息。

当您编写单元测试时,您不想访问数据库,因此您通常会模拟您的数据访问权限,这是您在此处所做的,通过创建模拟库。您遇到的问题是,因为您没有访问Entity Framework类,所以它不会为您填充域对象。通过创建RoomBooking列表,您已经完成了部分工作,但是您需要创建所有的被测系统所依赖的对象。

在基本级别,您只需更改创建roomBookings的方式即可包含缺失的信息。这样的事情可以解决问题:

var roomBookings = new List<RoomBooking>();
roomBookings.Add(new RoomBooking()
{
    Id = 1,
    BookingType = BookingType.PartyOrder,
    Date = new DateTime(2014, 11, 15),
    PartyRoomId = 2,
    TimeSlotId = 1,
    PartyRoom = new PartyRoom {
        Bookings = roomBookings
    }
});
roomBookings.Add(new RoomBooking()
{
    Id = 2,
    BookingType = BookingType.PartyOrder,
    Date = new DateTime(2014, 11, 15),
    PartyRoomId = 4,
    TimeSlotId = 3,
    PartyRoom = new PartyRoom {
        Bookings = roomBookings
    }
});
roomBookings.Add(new RoomBooking()
{
    Id = 3,
    BookingType = BookingType.PartyOrder,
    Date = new DateTime(2014, 11, 15),
    PartyRoomId = 5,
    TimeSlotId = 4,
    PartyRoom = new PartyRoom {
        Bookings = roomBookings
    }
});

请注意,我为每个PartyRoom创建了一个RoomBooking条目,并指向我正在创建的列表。这可能不是正确的做法(您可能需要为每个RoomBooking创建一个新的PartyRoom列表,其中只包含该会议室的预订,但没有看到您的数据库,我猜不到)

基本上,您需要创建测试和受测试系统所依赖的所有对象。

还有Autofixture这样的框架可以帮助您创建测试对象,值得您考虑。