gpt4 book ai didi

c# - FakeItEasy 说 MustHaveHappened 没有发生......但确实发生了

转载 作者:太空狗 更新时间:2023-10-29 19:56:02 28 4
gpt4 key购买 nike

我正在尝试对“服务层”/“应用程序外观层”方法进行单元测试。这是我尝试进行单元测试的方法:

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

在单元测试中,我无法访问在被测方法中创建的实际订单,我尝试做下一个最好的事情......采用下方法返回的订单的 DTO 版本测试,将订单的 DTO 版本映射回域模型订单的新实例,并确保在将其发送到 FakeItEasy 的 MustHaveHappened() 之前属性相同。

我调试了单元测试并查看了 ACTUAL Order 的属性与 FAKED Order 的属性......我向你保证,它们是相同的。此外,我可以通过调试确认确实调用了 _customerRepository.Save(order)。

问题.MustHaveHappened() 是否失败,因为我本质上是在发送 Order 对象的两个不同实例——即使它们的属性相同?即使属性相同,FakeItEasy 是否需要相同的输入参数实例来确保方法调用已经发生?

此外,关于我应该如何测试这类事情的任何建议(即编排/服务/“应用程序外观”/任何你想要调用它的层方法)?

最佳答案

Is .MustHaveHappened() failing because I'm essentially sending in two different instances of the Order object -- even though their properties are identical?

是的。 FakeItEasy 将使用 .Equals,它(除非您的类重写它)引用类型默认引用相等性。

(...) does FakeItEasy need the same instance of the input parameter to ensure that the method call has happened?

没有。您可以像这样进行自定义参数匹配:

A.CallTo(() => _orderRepository.Save(A<Order>.That.Matches(o =>
o.Status == "New" &&
o.Id == 10
))).MustHaveHappened();

但是,这个问题表明您的代码存在问题。从您的示例中可以清楚地看出您正在将 _customerRepository 作为依赖项注入(inject)。那太棒了。为什么不对 OrderFactory 做同样的事情?如果它是通过接口(interface)/基类依赖项注入(inject)的,那么您可以轻松地模拟(伪造)它并且您当前的问题将不存在。

如果您可以更改代码,我建议注入(inject)工厂(遵循简单的准则 - “没有 new 是个好消息!”)。如果没有,请使用自定义匹配器来验证订单属性,就像我在上面的示例中所做的那样。

关于c# - FakeItEasy 说 MustHaveHappened 没有发生......但确实发生了,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13937232/

28 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com