为什么我在使用包装功能时得到 'Call to unconfigured method'?

Why am I getting 'Call to unconfigured method' when using wrapped functionality?

使用 FakeItEasy 7.3.0 版。 在下面的代码中,我收到消息称未配置对方法 GetById 的调用,但我正在配置它。我做错了什么? GetById 方法没有重载。

var fakeConnection = A.Fake<IEventStoreConnection>();
var fakeResolver = A.Fake<IEventResolver>();
var logger = A.Fake<ILogger<DummyAggregateRepository>>();

var repository = new DummyAggregateRepository(fakeConnection, fakeResolver, logger);

var fakeRepository = A.Fake<DummyAggregateRepository>(
    o =>
    {
        o.Wrapping(repository);
        o.Strict();
    });

var aggregateId = Guid.NewGuid();

A.CallTo(() => fakeRepository.GetById(aggregateId, A<CancellationToken>._))
    .CallsWrappedMethod();

var fixture = new AutoFixture.Fixture();

var events1 = fixture.CreateMany<DummyAggregate.EventOne>(10).Cast<Event>();
var events2 = fixture.CreateMany<DummyAggregate.EventTwo>(10).Cast<Event>();

var events = events1.Union(events2).ToList();

A.CallTo(
        () => fakeRepository.GetEvents(
            "dummyAggregate-" + aggregateId.ToString("N"),
            aggregateId.ToString(),
            A<CancellationToken>._))
    .Returns(events);

var aggregate = await fakeRepository.GetById(aggregateId, default);

GetById 实现是虚方法

public virtual async Task<TAggregate> GetById(Guid aggregateId, CancellationToken ct)
        {
            ct.ThrowIfCancellationRequested();

            var streamName = this.GetStreamName(aggregateId);

            using var scope = EventStoreCommon.CreateScope(Tracer.Instance, nameof(this.GetById), streamName);

            var events = await this.GetEvents(streamName, aggregateId.ToString(), ct);

            if (events.Any() == false)
            {
                throw new AggregateNotFoundException(aggregateId, typeof(TAggregate));
            }

            var aggregate = new TAggregate();

            foreach (var @event in events)
            {
                aggregate.ApplyEvent(@event);
            }

            return aggregate;
        }

报告错误

FakeItEasy.ExpectationException: Call to unconfigured method of strict fake: MyCompany.EventStore.Test.AggregateRepositoryTests.DummyAggregateRepository...

FakeItEasy.ExpectationException
Call to unconfigured method of strict fake: MyCompany.EventStore.Test.AggregateRepositoryTests.DummyAggregateRepository.GetById(aggregateId: d8d0445d-7f82-4636-82fc-2e8f14be7f3d, ct: System.Threading.CancellationToken).
   at FakeItEasy.Core.StrictFakeRule.Apply(IInterceptedFakeObjectCall fakeObjectCall) in C:\projects\fakeiteasy\src\FakeItEasy\Core\StrictFakeRule.cs:line 53
   at FakeItEasy.Core.FakeManager.ApplyBestRule(IInterceptedFakeObjectCall fakeObjectCall) in C:\projects\fakeiteasy\src\FakeItEasy\Core\FakeManager.cs:line 276
   at FakeItEasy.Core.FakeManager.FakeItEasy.Core.IFakeCallProcessor.Process(InterceptedFakeObjectCall fakeObjectCall) in C:\projects\fakeiteasy\src\FakeItEasy\Core\FakeManager.cs:line 178
   at FakeItEasy.Creation.CastleDynamicProxy.CastleDynamicProxyGenerator.ProxyInterceptor.Intercept(IInvocation invocation) in C:\projects\fakeiteasy\src\FakeItEasy\Creation\CastleDynamicProxy\CastleDynamicProxyGenerator.cs:line 187
   at Castle.DynamicProxy.AbstractInvocation.Proceed()
   at Castle.Proxies.DummyAggregateRepositoryProxy.GetById(Guid aggregateId, CancellationToken ct)
   at MyCompany.EventStore.Test.AggregateRepositoryTests.GetByIdTests.When_Stream_Exists_Should_Create_Instance_Of_Aggregate_With_Applied_Events() in C:\github\MyCompany_2\libraries\eventstore\test\MyCompany.EventStore.Test\AggregateRepositoryTests\GetByIdTests.cs:line 131
   at System.Threading.Tasks.Task.<>c.<ThrowAsync>b__139_0(Object state)
   at Xunit.Sdk.AsyncTestSyncContext.<>c__DisplayClass7_0.<Post>b__1(Object _) in C:\Dev\xunit\xunit\src\xunit.execution\Sdk\AsyncTestSyncContext.cs:line 75

获取新代码和堆栈跟踪后更新。原答案左下方

我认为这是一个错误。

无聊的解释:

StrictWrapping 各自将规则添加到伪造对象规则列表的前面。这些规则适用于所有来电。第一条发现的与呼叫匹配的规则被触发。因此,在您的配置中,添加 Wrapping 使 Fake 尝试将所有调用转发给包装对象。然后Strict,所以现在假货会拒绝所有来电。

你会期望

A.CallTo(() => fakeRepository.GetById(aggregateId, A<CancellationToken>._))
    .CallsWrappedMethod();

添加一条规则,使传入的匹配 GetById 调用转发到包装方法,但 implementation of CallsWrappedMethod

似乎缺少第 127 行附近的 this.AddRuleIfNeeded() 调用。(您可以看到上面的 CallsBaseMethod 有这个调用。)

我已确认 CallsWrappedMethod 配置没有添加任何规则。自从在 FakeItEasy 6.0.0 (issue #1717).

中实施后可能已被破坏

我创建了issue #1870 which is now fixed and released as part of FakeItEasy 7.3.1


原始回复,错误,但确实要求提供更多信息:

可能是因为在严格伪造的存储库上调用了未配置的方法。

我们看不到 DummyAggregateRepository,所以这里会有一些猜测。基于前面没有错误,我 假设 GetById 是虚拟的或抽象的,因此您的调用应该传递给包装的实例。

当我读到你的问题时,我什么也没想到,但这种事情通常会在

时出现
  1. 调用了与预期不同的假对象,或者
  2. 调用了与预期不同的方法,通常是因为存在重载并且配置了错误的方法
  3. 调用了预期的假对象方法,但使用了意外参数

如果您编辑问题,请提供

  1. 您正在使用的 FakeItEasy 版本
  2. DummyAggregateRepository的定义,以及
  3. 返回的整个异常,包括堆栈跟踪

我们也许可以提供更好的帮助。