Reputation: 1153
I have an interface definition where the method has an out parameter defined
public interface IRestCommunicationService
{
TResult PerformPost<TResult, TData>(string url, TData dataToSend, out StandardErrorResult errors);
}
I have the following class that is using the above interface
public TripCreateDispatchService(IRestCommunicationAuthService restCommunicationService, ISettings settings)
{
_restCommunicationService = restCommunicationService;
_settings = settings;
}
public FlightAlert CreateTrip(string consumerNumber, PostAlertModel tripModel, out StandardErrorResult apiErrors)
{
url = .. code ommited
var result = _restCommunicationService.PerformPost<FlightAlert, PostAlertModel>(url), tripModel, out apiErrors);
return result;
}
In my unit tests I am trying to verify that the PerformPost Method of the RestCommunication object is called.
But no matter what I do, I cannot get Moq to verify that the method was called
public void DispatchService_PerformPost()
{
var consumerNumber = ...
var trip = ...
var result = ...
var apiErrors = new StandardErrorResult();
... code to setup mock data
_mockRestCommunicationService = new Mock<IRestCommunicationAuthService>();
_mockEestCommunicationService.Setup(x => x.PerformPost<string, PostAlertModel>(It.IsAny<string>(), It.IsAny<PostAlertModel>(), out apiErrors)).Verifiable();
_systemUnderTest.CreateTrip(consumerNumber, trip, out apiErrors);
_mockRestCommunicationService.Verify(m =>
m.PerformPost<StandardErrorResult, PostAlertModel>(
It.IsAny<string>(),
It.IsAny<PostAlertModel>(), out apiErrors
), Times.Once);
}
But I am receiving the following error
Moq.MockException :
Expected invocation on the mock once, but was 0 times:
m => m.PerformPost<StandardErrorResult,PostAlertModel>(It.IsAny<String>(), It.IsAny<PostAlertModel>(), .apiErrors)
No setups configured.
How do I go about verifying that the method was called.
I am using Moq and NUnit
UPDATE 1
As per the comment from Sunny, I have modified the test to use a callback as follows
var consumerNumber = ...
var trip = ...
var result = ...
StandardErrorResult apiErrors;
_mockRestCommunicationService.Setup(x => x.PerformPost<string, PostAlertModel>(
It.IsAny<string>(), It.IsAny<PostAlertModel>(), out apiErrors))
.Callback<string, PostAlertModel, StandardErrorResult>
((s, m, e) => e.Errors = new System.Collections.Generic.List<StandardError>()
{
new StandardError { ErrorCode = "Code", ErrorMessage = "Message" }
});
_systemUnderTest.CreateTrip(consumerNumber, trip, out apiErrors);
Assert.That(apiErrors.Errors, Is.Not.Null);
This is the error that is now being thrown when executing the test.
System.ArgumentException : Invalid callback. Setup on method with
parameters (String,PostAlertModel,StandardErrorResult&)
cannot invoke callback with parameters (String,PostAlertModel,StandardErrorResult).
at Moq.MethodCall.ThrowParameterMismatch(ParameterInfo[] expected, ParameterInfo[] actual)
at Moq.MethodCall.SetCallbackWithArguments(Delegate callback)
at Moq.MethodCallReturn`2.Callback(Action`3 callback)
This error is thrown at the Setup statement.
FYI. I am using Resharper 8 and using their test runner to execute my tests.
If I try to add the out parameter to the callback, the code will not compile.
I get the same error if I modify the setup to
_mockRestCommunicationService.Setup(x => x.PerformPost<string, PostAlertModel>(
It.IsAny<string>(), It.IsAny<PostAlertModel>(), out apiErrors))
.Callback
((string s, PostAlertModel m, StandardErrorResult e) => e.Errors = new System.Collections.Generic.List<StandardError>()
{
new StandardError { ErrorCode = "Code", ErrorMessage = "Message" }
});
Upvotes: 15
Views: 8242
Reputation: 2597
In the project I am working on we have used out It.Ref<T>.IsAny
where T is the out parameter type (Moq version 4.14). This is because out
is used as a parameter modifier, such that the value are passed by reference instead of by value.
In your case the verify method could look like this:
_mockRestCommunicationService.Verify(
_ => _.PerformPost<StandardErrorResult, PostAlertModel>(
It.IsAny<string>(),
It.IsAny<PostAlertModel>(),
out It.Ref<StandardErrorResult>.IsAny
),
Times.Once
);
To make sure no other unexpected invocations happened, you can also add:
_mockRestCommunicationService.VerifyNoOtherCalls()
Upvotes: 11
Reputation: 22310
It's better to actually use AAA and not verify the mock. Setup your method to return some specific result and assert that the result have been returned:
var myCommResult = new PostAlertModel();
_mockEestCommunicationService
.Setup(x => x.PerformPost<string, PostAlertModel>(It.IsAny<string>(), It.IsAny<PostAlertModel>(), out apiErrors)
.Returns(myCommResult);
var response = _systemUnderTest.CreateTrip(consumerNumber, trip, out apiErrors);
Assert.AreSame(myCommResult, response);
The above will validate that the method was called, based on the example code.
If for some reason, the code in the question is not really representative of the real code, and there is no way to assert on the return of the method, than you can use Callback instead, and put something in the errors so you can verify.
Something like:
_mockEestCommunicationService
.Setup(x => x.PerformPost<string, PostAlertModel>(It.IsAny<string>(), It.IsAny<PostAlertModel>(), out apiErrors))
.Callback( (string s, PostAlertModel m, StandardErrorResult e) => e.Add("Some error to test");
And later verify that apiErrors has the error you inserted in the callback.
Upvotes: 4