FakeConfigurationException when ReturnsLazily parameter implements parameter type
See original GitHub issueHello. 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:
- Created a year ago
- Comments:5 (4 by maintainers)
Top GitHub Comments
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.
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:
with
That’s even assuming that the InvalidCastException weren’t caught and transformed or suppressed by the production code…