FakeItEasy: простой Fake не используется - PullRequest
0 голосов
/ 09 ноября 2018

Я пытаюсь использовать 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. Я хочу перехватить вызов метода GetOrderForProcessing() (в методе Execute()) и заставить его вернуть мой жестко закодированный объект purchaseOrder. Но вместо этого я получаю другое возвращаемое значение (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() возвращает мой жестко запрограммированный объект, как и ожидалось. Два теста практически одинаковы, за исключением того, что метод GetOrderForProcessing() принимает параметр, а Execute() - нет.

1 Ответ

0 голосов
/ 09 ноября 2018

ExecuteTest терпит неудачу, потому что вы настраиваете подделку IPosMessageProcessor, а затем вызываете Execute на реальном PosMessageProcessor, _posMessageProcessor. _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();
}
...