FakeItEasy:未使用简单假货

FakeItEasy: Simple Fake not being used

我正在尝试使用 FakeItEasy(版本 4.9.1)为一些遗留代码创建单元测试。我创建了两个单元测试,其中一个按预期工作,另一个非常相似,尽管经过大量试验和错误但仍不起作用。

以下是似乎无法测试的方法的摘录:

public class PosMessageProcessor : IPosMessageProcessor
{
    public void Execute()
    {
        PurchaseOrderRepository repo = new PurchaseOrderRepository();
        ...
        try
        {
            m_PurchaseOrder = GetOrderForProcessing(repo);
            ...

这是我的测试:

[TestMethod]
[TestCategory("POS")]
public void ExecuteTest()
{
    // Arrange
    PurchaseOrder purchaseOrder = GetPurchaseOrder();
    IPosMessageProcessor fakePosMessageProcessor = A.Fake<IPosMessageProcessor>();
    A.CallTo(() => fakePosMessageProcessor.GetOrderForProcessing(A<IPurchaseOrderRepository>.Ignored)).Returns(purchaseOrder);

    // Act
    _posMessageProcessor.Execute();

    // Assert
    A.CallTo(() => fakePosMessageProcessor.GetOrderForProcessing(A<IPurchaseOrderRepository>.Ignored)).MustHaveHappened();
}

_posMessageProcessor 变量是 PosMessageProcessor class 的实例。我想捕获对 GetOrderForProcessing() 方法的调用(在 Execute() 方法中)并使其成为 return 我的硬编码 purchaseOrder 对象。但是我得到了另一个 return 值 (null)。为什么?

有效的单元测试测试 GetOrderForProcessing() 方法:

[TestMethod]
[TestCategory("POS")]
public void GetOrderForProcessingTest()
{
    // Arrange
    PurchaseOrder purchaseOrder = GetPurchaseOrder();
    IPurchaseOrderRepository fakePurchaseOrderRepository = A.Fake<IPurchaseOrderRepository>();
    A.CallTo(() => fakePurchaseOrderRepository.GetPurchaseOrderByOrderTrackingNumber(A<string>.Ignored)).Returns(purchaseOrder);

    // Act
    PurchaseOrder result = _posMessageProcessor.GetOrderForProcessing(fakePurchaseOrderRepository);

    // Assert
    A.CallTo(() => fakePurchaseOrderRepository.GetPurchaseOrderByOrderTrackingNumber(A<string>.Ignored)).MustHaveHappened();
    Assert.IsNotNull(result);
}

在这种情况下,调用 GetPurchaseOrderByOrderTrackingNumber() return 是我预期的硬编码对象。这两个测试实际上是相同的,除了 GetOrderForProcessing() 方法需要一个参数而 Execute() 没有。

ExecuteTest 失败,因为您配置了假的 IPosMessageProcessor,然后在真实的 PosMessageProcessor_posMessageProcessor 上调用了 Execute_posMessageProcessor,作为实际的 PosMessageProcessor,执行其常规代码路径,调用实际的 Execute,这将调用实际的 GetOrderForProcessing.

(请注意,您实际上可以从测试中删除 fakePosMessageProcessor 变量和对它的所有引用,行为将相同。)

我不推荐这种测试,但为了伪造 GetOrderForProcessing 并仍然测试实际的 Execute 代码,您必须编写类似

的测试
public void NewExecuteTest()
{
    // Arrange
    PurchaseOrder purchaseOrder = GetPurchaseOrder();

    // Get a fake PosMessageProcessor that falls back to original behaviour for all calls.
    IPosMessageProcessor fakePosMessageProcessor = A.Fake<PosMessageProcessor>(options => options.CallsBaseMethods());

    // Now fake out the GetOrderForProcessing call so we can test Execute.
    A.CallTo(() => fakePosMessageProcessor.GetOrderForProcessing(A<IPurchaseOrderRepository>.Ignored)).Returns(purchaseOrder);

    // Act
    fakePosMessageProcessor.Execute();

    // Assert
    A.CallTo(() => fakePosMessageProcessor.GetOrderForProcessing(A<IPurchaseOrderRepository>.Ignored)).MustHaveHappened();
}