FakeIseasy的第一步和Action类型的问题



我有以下(这里是简化的)代码,我想用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)"没有目标当调用没有目标的方法时,没有实现"继续",拦截者有责任模拟实现(设置返回值、输出参数等)

现在我有点困惑,不知道下一步该怎么办。

问题来自于你创建假的方式以及你以后期望它做什么:

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

什么基本方法?FakeIseasy不知道基类是什么,因此在第二种情况下会出现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的调用除外,该调用将重定向到实际实现。

最新更新