We're using Nunit, NSubstitute and AutoFixture to test a repository class that's built on top of Insight database...
[TestFixture]
public class CalculationResultsRepositoryTests
{
private IFixture _fixture;
private IDbConnection _connection;
private CalculationResultsRepository _calculationResultsRepository;
[SetUp]
public void Setup()
{
_fixture = new Fixture().Customize(new AutoConfiguredNSubstituteCustomization());
_connection = _fixture.Freeze<IDbConnection>();
_calculationResultsRepository = _fixture.Create<CalculationResultsRepository>();
}
[Test]
public void TestReturnsPagedCalculationResults()
{
//Arrange
var financialYear = _fixture.Create<int>();
var pagedResults = _fixture.Create<PagedResults<ColleagueCalculationResult>>();
_connection.QueryAsync(Arg.Any<string>(), Arg.Any<object>(), Arg.Any<IQueryReader<PagedResults<ColleagueCalculationResult>>>()).Returns(pagedResults);
//Act
var result = _calculationResultsRepository.PagedListAsync(financialYear);
//Assert
Assert.IsInstanceOf<PagedResults<ColleagueCalculationResult>>(result);
}
}
However, when running the test we're seeing the following exception:
System.Reflection.TargetInvocationException : Exception has been thrown by the target of an invocation. ----> NSubstitute.Exceptions.UnexpectedArgumentMatcherException : Argument matchers (Arg.Is, Arg.Any) should only be used in place of member arguments. Do not use in a Returns() statement or anywhere else outside of a member call. Correct use: sub.MyMethod(Arg.Any()).Returns("hi") Incorrect use: sub.MyMethod("hi").Returns(Arg.Any())
We're at a bit of a loss with how to resolve this, however at a guess it seems to be something to do with the return type being defined as a generic within a parameter on this particular overload of the QueryAsync() extension method within InsightDatabase:
public static Task<T> QueryAsync<T>(this IDbConnection connection, string sql, object parameters, IQueryReader<T> returns, CommandType commandType = CommandType.StoredProcedure, CommandBehavior commandBehavior = CommandBehavior.Default, int? commandTimeout = default(int?), IDbTransaction transaction = null, CancellationToken? cancellationToken = default(CancellationToken?), object outputParameters = null);
Does anybody know how to successfully mock this?
For completeness the method call we're trying to substitute is this:
var results = await _connection.QueryAsync("GetCalculationResults", new { FinancialYearId = financialYearId, PageNumber = pageNumber, PageSize = pageSize },
Query.ReturnsSingle<PagedResults<ColleagueCalculationResult>>()
.ThenChildren(Some<ColleagueCalculationResult>.Records));