How do I use Moq and DbFunctions in unit tests to prevent a NotSupportedException?

前端 未结 7 1711
借酒劲吻你
借酒劲吻你 2020-12-05 23:05

I\'m currently attempting to run some unit tests on a query that is running through the Entity Framework. The query itself runs without any issues on the live version, but t

7条回答
  •  情书的邮戳
    2020-12-05 23:48

    since i hit the same problem recently, and opted for a simpler solution, wanted to post it here.. this solution requires no Shims, Mocking, nothing expansive etc.

    1. Pass a 'useDbFunctions' boolean flag to your method with default value as true.
    2. When your live code executes, your query will use DbFunctions and everything will work. Due to the default value, callers need not worry about it.
    3. When your unit tests invoke the method to test, they can pass useDbFunctions: false.
    4. In your method, you can make use the flag to compose your IQueryable.. if useDbFunctions is true, use the DbFunctions to add the predicate to the queryable. if useDbFunctions is false, then skip the DbFunctions method call, and do an explicit C# equivalent solution.

    This way, your unit tests will check almost 95% of your method in parity with live code. You still have the delta of "DbFunctions" vs. your equivalent code, but be diligent about it and the 95% will look like a lot of gain.

    public System.Data.DataTable GetLinkedUsers(int parentUserId, bool useDbFunctions = true)
    {
        var today = DateTime.Now.Date;
    
        var queryable = from up in DB.par_UserPlacement
                    where up.MentorId == mentorUserId;
    
        if (useDbFunctions) // use the DbFunctions
        {
         queryable = queryable.Where(up => 
         DbFunctions.TruncateTime(today) >= DbFunctions.TruncateTime(up.StartDate)
         && DbFunctions.TruncateTime(today) <= DbFunctions.TruncateTime(up.EndDate));
        }  
        else
        {
          // do db-functions equivalent here using C# logic
          // this is what the unit test path will invoke
          queryable = queryable.Where(up => up.StartDate < today);
        }                    
    
        var query = from up in queryable
                    select new
                    {
                        up.UserPlacementId,
                        up.Users.UserId,
                        up.Users.FirstName,
                        up.Users.LastName,
                        up.Placements.PlacementId,
                        up.Placements.PlacementName,
                        up.StartDate,
                        up.EndDate,
                    };
    
        query = query.OrderBy(up => up.EndDate);
    
        return this.RunQueryToDataTable(query);
    }
    

    Unit tests will invoke the mthod as:

    GetLinkedUsers(parentUserId: 10, useDbFunctions: false);
    

    Because unit tests would have setup local DbContext entities, the C# logic/DateTime functions would work.

提交回复
热议问题