我正在尝试对“服务层”/“应用程序外观层”方法进行单元测试。这是我试图单元测试的方法:
// Create a new order in the database for a customer. Given a customer id,
// will create a new order and return an OrderDto for use in the presentation
// layer.
public OrderDto CreateOrderForCustomer(int customerId)
{
// Find the customer
var customer = _customerRepository.GetCustomerById(customerId);
// Create an order and apply special logic to get it ready for use.
var orderFactory = new OrderFactory();
var order = orderFactory.CreateOrder(customer);
// IMPORTANT: This is what I'm trying to unit test ...
_orderRepository.Save(order);
order.Status = "Editing";
// Using AutoMapper to turn this into a DTO that will be returned
// to the Presentation layer. The Mappings are created in the
// constructor and not depicted in this code snippet.
var orderDto = Mapper.Map<Order, OrderDto>(order);
return orderDto;
}
(注意……为了清楚起见,我在这里添加了大量的注释。我通常不那么健谈。)
由于这个方法的工作是编排领域层方法和持久层方法来创建一个空订单,持久化它,并将它作为一个简单的 DTO 返回,我认为这对于 FakeItEasy 来说是一项很棒的工作......我会确保那些关键方法正在被正确编排,以确保使用 FakeItEasy 的 MustHaveHappened() 调用它们。
因此,考虑到这一点,这是我创建的单元测试:
[TestMethod]
public void CreateOrderForCustomer_ValidCustomer_CreatesNewOrder()
{
// Arrange
var customer = _customerRepository.GetCustomerById(1);
Assert.AreEqual(0, customer.Orders.Count);
// Act
var orderDto = _orderEntryService.CreateOrderForCustomer(1);
// Assert
// Here I'm trying to make sure to re-create the order that was actually
// sent into the _customerRepository.Save() ... I should be able to
// simple un-map the OrderDto back to an Order, and undo the property
// change.
var order = Mapper.Map<OrderDto, Order>(orderDto);
order.Status = "New";
A.CallTo(() => _customerRepository.GetCustomerById(1)).MustHaveHappened();
// **THIS CAUSES AN EXCEPTION**
A.CallTo(() => _orderRepository.Save(order)).MustHaveHappened();
Assert.AreEqual(1, customer.Orders.Count);
}
在单元测试中,我无法访问在被测方法中创建的 ACTUAL Order,我尝试做下一件最好的事情......取被测试方法返回的 Order 的 DTO 版本,map Order 的 DTO 版本返回到域模型 Order 的新实例,并在将其发送到 FakeItEasy 的 MustHaveHappened() 之前确保属性相同。
我已经调试了单元测试并查看了 ACTUAL Order 的属性与 FAKED Order 的属性……我向你保证,它们是相同的。此外,我可以通过调试确认 _customerRepository.Save(order) 确实被调用了。
问题 .MustHaveHappened() 是否失败是因为我实际上是在发送 Order 对象的两个不同实例——即使它们的属性相同?即使属性相同,FakeItEasy 是否需要输入参数的相同实例才能确保方法调用发生?
此外,关于我应该如何测试这类事情(即编排/服务/“应用程序外观”/what-ever-you-want-to-call-it layer 方法)的任何建议?