I have an interface like so:
public interface IStatisticsCollector : IDisposable
{
Task Measure(string metricName, decimal value, IDictionary<string, string> tags = null);
}
I am injecting this IStatisticsCollector into my class and using it like this:
var stopwatch = new Stopwatch();
await dataCollector.Measure("rbk_init", stopwatch.ElapsedMilliseconds);
...
await dataCollector.Measure("rbk_compiled", stopwatch.ElapsedMilliseconds);
...
Setting up my unit test to verify that I am recording all the statistics points I want, I mock the IStatisticsCollector:
private readonly Mock<IStatisticsCollector> _statisticsCollector = new Mock<IStatisticsCollector>();
_statisticsCollector.Setup(x => x.Measure(It.IsAny<string>(), It.IsAny<long>(), It.IsAny<IDictionary<string, string>>())).Verifiable();
When I run my unit test, my verification fails on this line:
//assert
_statisticsCollector.Verify(
x => x.Measure(It.IsAny<string>(), It.IsAny<long>(), It.IsAny<IDictionary<string, string>>()), Times.Exactly(5));
...with the following message:
Moq.MockException :
Expected invocation on the mock exactly 5 times, but was 0 times: x => x.Measure(It.IsAny<string>(), (decimal)It.IsAny<long>(), It.IsAny<IDictionary<string, string>>())
Configured setups:
IStatisticsCollector x => x.Measure(It.IsAny<string>(), (decimal)It.IsAny<long>(), It.IsAny<IDictionary<string, string>>())
Performed invocations:
IStatisticsCollector.Measure("rbk_init", 31, null)
IStatisticsCollector.Measure("rbk_compiled", 35, null)
IStatisticsCollector.Measure("rbk_stored", 36, null)
IStatisticsCollector.Measure("rbk_db_updated", 352, null)
IStatisticsCollector.Measure("rbk_completed", 361, null)
at Moq.Mock.VerifyCalls(Mock targetMock, InvocationShape expectation, LambdaExpression expression, Times times, String failMessage) in C:\projects\moq4\src\Moq\Mock.cs:line 378
... this was strange because it looks like it captured 5 matching invocations, but apparently didn't consider any of them to actually be matches. Now I postulated this might be related to the fact that the stopwatch's ElapsedMilliseconds was a long but the interface was expecting a decimal (with an implicit cast), so I changed the verify to look for It.IsAny<decimal>(), but that got me an unexpected result:
Moq.MockException :
Expected invocation on the mock exactly 5 times, but was 1 times: x => x.Measure(It.IsAny<string>(), It.IsAny<decimal>(), It.IsAny<IDictionary<string, string>>())
Configured setups:
IStatisticsCollector x => x.Measure(It.IsAny<string>(), It.IsAny<decimal>(), It.IsAny<IDictionary<string, string>>())
Performed invocations:
IStatisticsCollector.Measure("rbk_init", 28, null)
at Moq.Mock.VerifyCalls(Mock targetMock, InvocationShape expectation, LambdaExpression expression, Times times, String failMessage) in C:\projects\moq4\src\Moq\Mock.cs:line 378
It found one... and only one. There doesn't seem to be an exception thrown, so I don't know why there would only be one.
I also noted the null value on the optional argument, and tried to verify against a null value instead of an IDictionary<string, string>, but this was similarly fruitless.
Can someone explain this behavior? What do I need to do to fix my test?