0

Given I have a wrapped instance like this, where Resolve method injects dependencies

    var handler = this.Resolve<DeletePaymentCardHandler>();

    var wrapperHandler = A.Fake<DeletePaymentCardHandler>(
        o => o.Wrapping(handler));
    
    A.CallTo(() => wrapperHandler.EnsurePaymentCardCanBeDeleted(A<DeletePaymentCard>._, A<CancellationToken>._ ))
     .Returns(Task.CompletedTask);
    
    await wrapperHandler.Handle(command, CancellationToken.None);

Where 'Handle' method is implemented like this

public async Task Handle(DeletePaymentCard msg, CancellationToken cancellationToken)
{
     await this.EnsurePaymentCardCanBeDeleted(msg, cancellationToken);

     var instance = await this.repository.GetById<Domain.CustomerFundingSources>(msg.CustomerId, cancellationToken);

     instance.Process(msg);

     await this.repository.Save(instance);
}

public virtual async Task EnsurePaymentCardCanBeDeleted(DeletePaymentCard command, CancellationToken cancellationToken)
{
    return Task.CompletedTask
}

What I am observing is that instead of this call in Handle calling injected repository it calls proxy created by FakeItEasy?

var instance = await this.repository.GetById<Domain.CustomerFundingSources>(msg.CustomerId, cancellationToken);

I thought point was to be able to intercept only calls to some methods and rest should call wrapped instance methods? From documentation:

"By default, calls to a wrapping fake that have not been explicitly configured will be forwarded to the wrapped object."

epitka
  • 17,275
  • 20
  • 88
  • 141

1 Answers1

0

It's impossible to be completely sure without access to all the code of DeletePaymentCardHandler, but here's what it looks like to me:

Handle is not virtual, so will be executing the code in DeletePaymentCardHandler, bypassing FakeItEasy entirely.

In Handle, the GetById method is called on the repository field (accessing repository is not a method invocation, and FakeItEasy can't intercept field access), which will most likely have been initialized by the faked DeletePaymentCardHandler class's constructor.

If the repository field is initialized from a constructor argument, FakeItEasy will have supplied a Dummy repository to satisfy that constructor argument. The repository type is very likely something that FakeItEasy can fake, so the value would be a Fake.

Thus, in wrappedHandler.Handle, the real Handle code is calling the fake repository.

If you want some other behaviour, then maybe the fake needs to be supplied the same repository as the wrapped handler. Or Handle could access the repository via a virtual property or method, which would be intercepted by FakeItEasy and forwarded to the wrapped handler, which would then access the repository supplied by the Resolve method.

Blair Conrad
  • 233,004
  • 25
  • 132
  • 111