I am trying to Moq a Rabbit MQ method.
ValueTask BasicPublishAsync<TProperties>(string exchange, string routingKey,
bool mandatory, TProperties basicProperties, ReadOnlyMemory<byte> body,
CancellationToken cancellationToken = default)
where TProperties : IReadOnlyBasicProperties, IAmqpHeader;
What is the correct form of:
mockRabbitModel.Setup(a => a.BasicPublishAsync<It.IsSubtype<IAmqpHeader>>(
It.IsAny<string>() /*exchange*/,
It.IsAny<string>() /*routingKey*/,
It.IsAny<bool>() /* mandatory*/,
// ??????,
It.Is<ReadOnlyMemory<byte>>(b =>
this.TestSentMessage(b, (expected, actual) =>
Assert.AreEqual(expected, actual.Command))),
It.IsAny<CancellationToken>()));
Moq can't work with TProperties directly and I have seen various ideas for mapping the argument with ??????
As you have used It.IsSubtype<IAmqpHeader>
as the generic parameter for the BasicPublishAsync
, you should use the same type for the basicProperties
wrapped into a It.IsAny
.
Here is a simplified version of your code:
public interface IFoo
{
ValueTask BasicPublishAsync<TProperties>(string key1, TProperties properties);
}
Then the mocking should be done like this:
var foo_mock = new Mock<IFoo>();
foo_mock.Setup(foo => foo.BasicPublishAsync<It.IsSubtype<int>>(It.IsAny<string>(), It.IsAny<It.IsSubtype<int>>()))
.Returns(() => ValueTask.FromException(new Exception("BlahBlah")));
Here you can find a working sample code: https://dotnetfiddle.net/zSEE5D
UPDATE #1
To tackle the multi interface constraint you can introduce a custom TypeMatcher
:
The interfaces:
public interface IFoo
{
ValueTask BasicPublishAsync<TProperties>(string key1, TProperties properties) where TProperties: IA, IB;
}
public interface IA {}
public interface IB {}
internal interface IAB: IA, IB {} // just for testing
The type matcher
[TypeMatcher]
public class FooTypeMatcher<T> : IA, IB, ITypeMatcher
where T : IA, IB
{
bool ITypeMatcher.Matches(Type typeArgument)
{
return typeof(T).IsAssignableFrom(typeArgument);
}
}
The mock setup:
var foo_mock = new Mock<IFoo>();
foo_mock.Setup(foo => foo.BasicPublishAsync<FooTypeMatcher<IAB>>(It.IsAny<string>(), It.IsAny<FooTypeMatcher<IAB>>()))
.Returns(() => ValueTask.FromException(new Exception("BlahBlah")));
Here you can find a working sample code: https://dotnetfiddle.net/5kOz8W