первые шаги с FakeItEasy и проблемы с типом действия - PullRequest
3 голосов
/ 29 января 2012

У меня есть следующий (здесь упрощенный) код, который я хочу проверить с помощью FakeItEasy .

public class ActionExecutor : IActionExecutor
{
    public void TransactionalExecutionOf(Action action)
    {
        try
        {
           // ...  
           action();
           // ... 
        }
        catch
        {
           // ...
           Rollback();
        }
    }

    public void Commit()
    {    }

    public void Rollback()
    {    }
}

public class Service : IService
{
    private readonly IRepository _repository;

    private readonly IActionExecutor _actionExecutor;

    // ctor for CI

    public void ServiceMethod(string name)
    {
        _actionExecutor.TransactionalExecutionOf(() =>
        {
            var item = _repository.FindByName(ItemSpecs.FindByNameSpec(name));
            if (item == null) throw new ServiceException("Item not found");

            item.DoSomething();
            _actionExecutor.Commit(); 
        }
    }
}

Я хочу проверить, что ServiceException выброшено, поэтому я настроил свойтакой тест

var repo = A.Fake<IRepository>();
A.CallTo(() => repo.FindByName(A<ISpec<Item>>.Ignored))
 .Returns(null);

var executor = A.Fake<IActionExecutor>();
executor.Configure()
        .CallsTo(x => x.Rollback()).DoesNothing();
executor.Configure()
        .CallsTo(x => x.Commit()).DoesNothing();
executor.Configure()
        .CallsTo(x => x.TransactionalExecutionOf(A<Action>.Ignored))
        .CallsBaseMethod();

Со следующим кодом

var service = new Service(executor, repo);
service.ServiceMethod("notExists")
       .Throws(new ServiceException());

я получаю следующее сообщение

Текущий прокси-генератор не может перехватить указанный метод дляследующая причина: - Запечатанные методы не могут быть перехвачены.

Если я вызываю метод непосредственно в службе, как

var service = new Service(executor, repo);
service.ServiceMethod("NotExists");

, я получаю это сообщение

Это ошибка DynamicProxy2: перехватчик попытался выполнить «Выполнить» для метода «Void TransactionalExecutionOf (System.Action)», который не имеет цели.При вызове метода без цели нет реализации, к которой следует «переходить», и перехватчик обязан имитировать реализацию (установить возвращаемое значение, аргументы и т. Д.)

Теперь я немного запуталсяи не знаю, что делать дальше.

1 Ответ

6 голосов
/ 29 января 2012

Проблемы возникают из-за того, как вы создаете фальшивку, и того, что вы впоследствии ожидаете от нее:

var executor = A.Fake<IActionExecutor>();
// ...
executor.Configure()
    .CallsTo(x => x.TransactionalExecutionOf(A<Action>.Ignored))
    .CallsBaseMethod();

Какой базовый метод ? FakeItEasy понятия не имеет, что такое базовый класс, и, следовательно, исключение DynamicProxy2 во втором случае. Вы можете создать частичное макетирование следующим образом:

var executor = A.Fake<ActionExecutor>();

Обратите внимание, что мы основываемся на фактической реализации, а не на интерфейсе

Это, однако, создает новый набор проблем, поскольку методы в ActionExecutor не являются виртуальными, и поэтому перехватчик не может их правильно перехватить. Чтобы ваша текущая настройка работала, вам нужно изменить ActionExecutor и сделать (все) методы виртуальными.

Однако вы можете (или даже должны) хотеть избежать изменений существующего кода (что иногда может даже не быть вариантом). Затем вы можете настроить вашу IActionExecutor подделку следующим образом:

var executor = A.Fake<IActionExecutor>();
A.CallTo(() => executor.TransactionalExecutionOf(A<Action>.Ignored))
    .Invokes(f => new ActionExecutor()
        .TransactionalExecutionOf((Action)f.Arguments.First())
    );

Это позволит вам работать с поддельным объектом, за исключением вызова TransactionalExecutionOf, который будет перенаправлен на фактическую реализацию.

...