Search code examples
c#unit-testingentity-framework-4mockingmoq

How to mock LINQ to Entities helpers such as 'SqlFunctions.StringConvert()'


I am using EF 4 and is trying to unit test the follow line using Moq:

var convertError = models
             .Where(x => SqlFunctions.StringConvert((decimal?) (x.convert ?? 0)) == "0")
             .Any();

and it seems like SqlFunctions.StringConvert() will throw if it detects the context is mocked.

It gives an error saying:

This function can only be invoked from LINQ to Entities

Is it possible to tell SqlFunctions.StringConvert to return a mock object so I can get rid of this error?


Solution

  • No it is not possible because the function's implementation looks like:

    [EdmFunction("SqlServer", "STR")]
    public static string StringConvert(decimal? number, int? length)
    {
        throw EntityUtil.NotSupported(Strings.ELinq_EdmFunctionDirectCall);
    }
    

    You cannot use Moq to fake this function. You need more powerful mocking framework which will allow you replacing static function call - probably Microsoft Fakes, TypeMock Isolator or JustMock.

    Or you need to think about your testing approach because mocking the context is the wrong idea. You should instead have something like:

    var convertError = myQueryProvider.ConvertQuery(x.convert); 
    

    Where queryProvider will be your mockable type hiding your query. Query is database related logic and it should be tested against the real database. Code around your query is your application logic and it should be unit tested - the best solution to test them both correctly is simply to separate them through some interface (query provider in this case but people often go with a full specific repository). This principle comes from separation of concerns - query execution is separate concern so it is placed into its own method which is tested separately.