3

Have a LINQ query expression (below) that want to test mocking the Entity Framework. To mock I am using the code: Entity Framework Testing with a Mocking Framework This works for other queries but doesn't work for this

var query = from vwPs in _reportingDbContext.VwAccountNumber
join ps in _reportingDbContext.PaymentSummary
  on new
  {
      Key1 = vwPs.Id,
      Key2 = vwPs.AccountNumber,
      Key3 = true,
      Key4 = true
  }
     equals
     new
     {
         Key1 = ps.Id,
         Key2 = ps.AccountNumber,
         Key3 = ps.PaymentDate >= fromDateTime,
         Key4 = ps.PaymentDate < toDateTime
     }
     into viewJoinPayment
from ps in viewJoinPayment.DefaultIfEmpty()
join prg in generatedReportIds
     on ps.PaymentRef equals prg
     into paymentJoinGenerated
from prgRow in paymentJoinGenerated.DefaultIfEmpty()
where vwPs.Id == Id
select new
{
    vwPs.AccountNumber,
    Payments = ps,
    ReportGenerated = prgRow
};

When execute the query the value in '_inner' at this point in the code

internal class TestDbAsyncEnumerator<T> : IDbAsyncEnumerator<T> {
    //...
    public Task<bool> MoveNextAsync(CancellationToken cancellationToken) 
    { 
        return Task.FromResult(_inner.MoveNext()); 
    }
    //...

}

? _inner {System.Linq.Enumerable.WhereSelectEnumerableIterator<<>f__AnonymousType11<<>f__AnonymousType10<<>f__AnonymousType9<<>f__AnonymousType7>, LL.Core.DataAccess.Models.PaymentSummaryEntity>, System.Collections.Generic.IEnumerable>, int>, <>f__AnonymousType12>} Current: null
Results View: Expanding the Results View will enumerate the IEnumerable

and when it executes the MoveNext() get exception

? _inner.MoveNext() '_inner.MoveNext()' threw an exception of type 'System.NullReferenceException' Data: {System.Collections.ListDictionaryInternal} HResult: -2147467261 HelpLink: null InnerException: null Message: "Object reference not set to an instance of an object." Source: "Anonymously Hosted DynamicMethods Assembly" StackTrace: " at lambda_method(Closure , <>f__AnonymousType92 )\r\n at System.Linq.Enumerable.<GroupJoinIterator>d__404.MoveNext()\r\n at System.Linq.Enumerable.d__223.MoveNext()\r\n at System.Linq.Enumerable.WhereSelectEnumerableIterator2.MoveNext()" TargetSite: {Int32 lambda_method(System.Runtime.CompilerServices.Closure, <>f__AnonymousType92[<>f__AnonymousType72[LL.Core.DataAccess.Models.VwAccountNumberEnt ity,System.Collections.Generic.IEnumerable`1[LL.Core.DataAccess.Models.PaymentSummaryEntity]],LL.Core.DataAccess.Models.PaymentSummaryEntity])}

Tried few changes including the one suggested in here DbSet mock, no results while calling ToList secondly

but still get the same problem. Please, can anybody give some light?

Verify query implementation with integration tests is not an option, as boss wants this to be tested at unit test level as all the other queries.

UPDATE: Thanks @Eduard Malakhov this is something tried. If remove the both 'DefaultIfEmpty' and run the query it doesn't throw the exception. But how can avoid the exception with the DefaultIfEmpty? How can I modify the mocking code to check this case, as the exception is not happening with a not mocked call?

var query = from vwPs in _charityReportingDbContext.VwCharityAccountNumber
join ps in _charityReportingDbContext.PaymentSummary
  on new
  {
      Key1 = vwPs.CharityId,
      Key2 = vwPs.AccountNumber,
      Key3 = true,
      Key4 = true
  }
     equals
     new
     {
         Key1 = ps.CharityId,
         Key2 = ps.AccountNumber,
         Key3 = ps.PaymentDate >= fromDateTime,
         Key4 = ps.PaymentDate < toDateTime
     }
     into viewJoinPayment
select new
{
    vwPs.AccountNumber,
};
Community
  • 1
  • 1
  • 1
    Just a guess: twice in that statement you're calling on **DefaultIfEmpty()** which would result in a nuill reference in case the respective enumerable is empty and might later lead to a **NullReferenceException**. What if you removed these calls and use empty emuerables instead? – Eduard Malakhov Jan 27 '17 at 17:35
  • @EduardMalakhov thanks, your explanation helped me to decide to implement my 'solution' below. Maybe mocking the EF is not the way to go and should use an in-memory database as others suggest in other posts. – Ricardo stands with Ukraine Jan 30 '17 at 09:41
  • 1
    I hope your boss has an educated opinion about this. *My* opinion is that mocking EF is hopeless. The tests build a dream world of their own that is fundamentally different from the real data access world. LINQ queries executed as SQL in a database won't throw NRE's where LINQ-to-object queries do, to mention only one important difference. When it comes to testing EF functions, use integration tests. Unit tests for the rest. – Gert Arnold Jan 30 '17 at 22:02
  • @Riga Did you find anyother way to mock the linq query which contains DefaultIfEmpty() in it. I too face the same problem, and cant able to mock queries with these kind of cases. – Dinesh M Sep 12 '18 at 10:26
  • 1
    At the end was decided to use a stored procedure instead. We didn't find an alternative solution. – Ricardo stands with Ukraine Sep 12 '18 at 14:42

1 Answers1

0

My hacky 'solution' (is Friday and want to go home :). Removes the exception but unfortunately, doesn't give right results.

public Task<bool> MoveNextAsync(CancellationToken cancellationToken){ 
try
{
    return Task.FromResult(_inner.MoveNext());
}
catch (Exception ex)
{
    return Task.FromResult(false);
}}