For this code and Strict mode I get :
MockException: SendAsync(null, CancellationToken) invocation failed with mock behavior Strict.
All invocations on the mock must have a corresponding setup.
For Loose mode result is null, and not an instance of HttpResponseMessage.
But should it be like that if I defined behaviour for public abstract method?!
void Main()
{
var method = typeof(TestHandler).GetMethods(BindingFlags.NonPublic | BindingFlags.Instance).Single(m => m.Name == "SendAsync");
var mock = new Mock<TestHandler>(MockBehavior.Strict);
mock.Setup(x => x.MockableSendAsync(It.IsAny<HttpRequestMessage>(), It.IsAny<CancellationToken>())).ReturnsAsync(new HttpResponseMessage());
var result = method.Invoke(mock.Object, new object[] { null, CancellationToken.None}) as Task<HttpResponseMessage>;
result.Wait();
}
public abstract class TestHandler : HttpMessageHandler
{
public abstract Task<HttpResponseMessage> MockableSendAsync(HttpRequestMessage request, CancellationToken cancellationToken);
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
return this.MockableSendAsync(request, cancellationToken);
}
}
I expect that protected overridden method works as it is.
Moreover, whenever I make it
protected sealed override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
Moq is happy, and everything works. The only problem is that in reality class is defined in F#, and F# does not support sealed methods.
Disclaimer: The following info is valid for Moq 4.x (which lives at https://github.com/moq/moq4), it may not be accurate for Moq 5.x (this repository).
This is expected behavior. Strict mode means that you must provide a setup for all methods you are calling. The methods' accessibility (public vs. protected) doesn't matter. What does matter is that rule holds only for methods that are interceptable by Moq; this excludes sealed, non-virtual, and static methods.
So (a) use either a loose mock together with CallBase = true, or (b) add a setup for your protected SendAsync method: mock.Protected().Setup("SendAsync", ...).CallBase().
Thanks, now it is clear. What are the changes for Moq 5.x?
Still not decided on how protected setups would work on v5. You can follow https://github.com/moq/moq/issues/51.
Thanks
I am going to close this issue since it is now in this repo, and an answer for Moq v4 has already been given above.
Most helpful comment
Still not decided on how protected setups would work on v5. You can follow https://github.com/moq/moq/issues/51.
Thanks