I work on a project which doesn't have an integration tests setup.
When I work on some backend task I need to have some test coverage for the stuff which is related to the interaction with the database.
I use EF Core 3.1, and because it already implements a repository pattern, I'm able to create extension methods per different entities.
And here the thing appears. Each LINQ query is translated into pure SQL. This also means that the logic of the query must behave exactly the same as translated SQL code.
I've checked and I'm allowed to write unit tests against non-async methods however in the case of the Async methods it doesn't seem to be that trivial.
For example, I have the following extension method:
public static class PostcodeExclusionExtension
{
public static bool CheckPostcodeIsSupported(this IQueryable<PostcodeExclusion> postcodeExclusion, int customerId, string postcode) =>
!postcodeExclusion.Any(ApplyIsSupportedExpression(customerId, postcode));
public static async Task<bool> CheckPostcodeIsSupportedAsync(this IQueryable<PostcodeExclusion> postcodeExclusion, int customerId, string postcode) =>
!await postcodeExclusion.AnyAsync(ApplyIsSupportedExpression(customerId, postcode));
private static Expression<Func<PostcodeExclusion, bool>> ApplyIsSupportedExpression(int customerId, string postcode)
{
postcode = postcode.Replace(" ", "").ToUpper();
postcode = postcode.Insert(postcode.Length - 3, " ");
var postcodeMatches = Enumerable.Range(0, postcode.Length)
.Select(x => postcode.Substring(0, x + 1))
.ToArray();
return x => x.CustomerID == customerId && postcodeMatches.Contains(x.Postcode);
}
}
This is unit tests coverage(written in xUnit):
public static int validCustomerId = 1;
public const string validPostcode = "SW1A0AA";
public static IEnumerable<object[]> CheckPostcodeExclusion_should_validate_postcode_Inputs = new List<object[]>
{
new object[] { true, validPostcode, validCustomerId, new List<PostcodeExclusion> { new PostcodeExclusion() { CustomerID = validCustomerId, Postcode = "A" } } },
new object[] { true, validPostcode, validCustomerId, new List<PostcodeExclusion> { new PostcodeExclusion() { CustomerID = validCustomerId, Postcode = "SX" } } },
//other test cases...
};
[Theory]
[MemberData(nameof(CheckPostcodeExclusion_should_validate_postcode_Inputs))]
public async Task CheckPostcodeExclusion_should_validate_postcode(bool expectedPostcodeIsSupported, string postcode, int customerId, IEnumerable<PostcodeExclusion> postcodeExclusionSet)
{
var isSupported = await postcodeExclusionSet.AsQueryable().CheckPostcodeIsSupportedAsync(customerId, postcode);
Assert.Equal(expectedPostcodeIsSupported, isSupported);
}
When I run the test against the Async
method I'm getting
The provider for the source IQueryable doesn't implement IAsyncQueryProvider. Only providers that implement IAsyncQueryProvider can be used for Entity Framework asynchronous operations.
I found this workaround however it only works for the EF core 2.2. I tried to somehow implement a similar idea for EF core 3.1 but without a result. At the moment I covered the non-async method with tests however I use Async one in the production. Better having something than nothing... Any ideas? Cheers