为什么我在使用包装功能时得到 '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
获取新代码和堆栈跟踪后更新。原答案左下方
我认为这是一个错误。
无聊的解释:
Strict
和 Wrapping
各自将规则添加到伪造对象规则列表的前面。这些规则适用于所有来电。第一条发现的与呼叫匹配的规则被触发。因此,在您的配置中,添加 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
是虚拟的或抽象的,因此您的调用应该传递给包装的实例。
当我读到你的问题时,我什么也没想到,但这种事情通常会在
时出现
- 调用了与预期不同的假对象,或者
- 调用了与预期不同的方法,通常是因为存在重载并且配置了错误的方法
- 调用了预期的假对象方法,但使用了意外参数
如果您编辑问题,请提供
- 您正在使用的 FakeItEasy 版本
DummyAggregateRepository
的定义,以及
- 返回的整个异常,包括堆栈跟踪
我们也许可以提供更好的帮助。
使用 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
获取新代码和堆栈跟踪后更新。原答案左下方
我认为这是一个错误。
无聊的解释:
Strict
和 Wrapping
各自将规则添加到伪造对象规则列表的前面。这些规则适用于所有来电。第一条发现的与呼叫匹配的规则被触发。因此,在您的配置中,添加 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
是虚拟的或抽象的,因此您的调用应该传递给包装的实例。
当我读到你的问题时,我什么也没想到,但这种事情通常会在
时出现- 调用了与预期不同的假对象,或者
- 调用了与预期不同的方法,通常是因为存在重载并且配置了错误的方法
- 调用了预期的假对象方法,但使用了意外参数
如果您编辑问题,请提供
- 您正在使用的 FakeItEasy 版本
DummyAggregateRepository
的定义,以及- 返回的整个异常,包括堆栈跟踪
我们也许可以提供更好的帮助。