question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

FakeConfigurationException when ReturnsLazily parameter implements parameter type

See original GitHub issue

Hello. I recently started to use FakeItEasy for my projects and I love it ❤. However, there is small thing that annoyed me when I tried to mock my MediatR commands and queries. I always have to specify the base type of the command (IRequest<T>), instead of the actual implementation when specifying a return value using ReturnsLazily. If I use IRequest<T>, as defined by the interface, then I must cast the request object to the actual implementation in the value producer, otherwise I get a FakeConfigurationException.

I do not know if this behavior is intentional or if changing it could break something, but it would make mocking MediatR requests easier to read.

I tried to resolve this by changing the type check of IsCallSignatureSatisfiedByValueProducerSignature to use IsAssignableFrom when comparing the call and value producer types and it seemed to work.

Here is the test case:

namespace FakeItEasy.Tests;
using System.Threading.Tasks;
using Xunit;

public interface IRequest<T> {}

public class MyCommand : IRequest<int>
{
    public int Value { get; set; }

    public MyCommand(int value)
    {
        this.Value = value;
    }
}

public interface ISender
{
    Task<TResponse> Send<TResponse>(IRequest<TResponse> request);
}

public class ReturnsLazilyTests
{
    [Fact]
    public async Task ReturnsLazily_accepts_implementation_of_call_method_parameter_type()
    {
        // Arrange
        var senderMock = A.Fake<ISender>();
        var command = new MyCommand(42);

        A.CallTo(() => senderMock.Send(A<MyCommand>._))
            // This works as expected.
            //.ReturnsLazily((IRequest<int> c) => ((MyCommand)c).Value + 1);
            // This will throw a FakeConfigurationException.
            .ReturnsLazily((MyCommand c) => c.Value + 1);

        // Act
        await senderMock.Send(command).ConfigureAwait(false);

        // Assert
        A.CallTo(() => senderMock.Send(A<MyCommand>._))
            .MustHaveHappened();
    }
}

Issue Analytics

  • State:closed
  • Created a year ago
  • Comments:5 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
C-574commented, Jul 17, 2022

Yeah, I already expected that it wouldn’t be that easy 😄.

So, casting the IRequest object is the only/correct way of mocking such a test case if I understand that correctly. It now makes sense to me why it works like that.

Thank you both for answering.

0reactions
blairconradcommented, Jul 16, 2022

As usual, better-put than what I had, @thomaslevesque. Thanks. The risk of a non-MyCommand being passed to the overridden method is always there. And a runtime (worse, during the Act phase) failure can be more difficult to detect and interpret than a failure during the Arrange phase.

compare:

System.InvalidCastException :
  Unable to cast object of type 'NonMyCommandIRequestOfInt' to type 'FakeItEasyQuestions.MyCommand'

with

FakeItEasy.Configuration.FakeConfigurationException :
  The faked method has the signature (FakeItEasyQuestions.IRequest`1[System.Int32]),
  but returns lazily was used with (FakeItEasyQuestions.MyCommand).

That’s even assuming that the InvalidCastException weren’t caught and transformed or suppressed by the production code…

Read more comments on GitHub >

github_iconTop Results From Across the Web

Not sure if this was already mentioned - method signature ...
The idea is that if you run out of type parameters then you fall back to using ReturnsLazily(Func<FakeItEasy.Core.
Read more >
FakeItEasy ReturnsLazily with out parameter
I would like to see how the arguments are passed on, so I'm using ReturnsLazily. Here is my attempt: long resSize; A.CallTo(() => ......
Read more >
Specifying a Fake's Behavior - FakeItEasy Succinctly Ebook
Sometimes return values that are determined at runtime are not known at design time when using FakeItEasy. A fake of a type that...
Read more >
Specifying Return Values
Sometimes a desired return value won't be known at the time the call is configured. ReturnsNextFromSequence and ReturnsLazily can help with that.
Read more >
Chocolatey Software | crane 0.2.0.14
NullReferenceException">The <paramref name="obj"/> parameter is null. ... It is not an error to return components that do not implement ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found