title: Unit testing using EF Core InMemoryDatabase along with Moq mocks
body: <p>I am using EF Core 6.0.x + NUnit + Moq. Below example is strongly anonymized, the real scenario actually makes sense.</p>
  <p>I have a DbContext:</p>
  <pre><code>public class MyDbContext : DbContext
  {        
      public virtual DbSet&lt;Foo&gt; Foos { get; set; }
  
      public MyDbContext(DbContextOptions&lt;MyDbContext&gt; options) : base(options) { }
      
      public virtual void PreSaveActions()
          =&gt; throw new NotImplementedException(); //Here I've got something that must be done pre-save.
  
      public override int SaveChanges()
      {
          PreSaveActions();
          return base.SaveChanges();
      }
  }
  </code></pre>
  <p>I have a method similar to this:</p>
  <pre><code>public class SafeRemover
  {
      private readonly IDbContextFactory&lt;MyDbContext&gt; _contextFactory;    
  
      public SafeRemover(IDbContextFactory&lt;MyDbContext&gt; contextFactory)
      {
          _contextFactory = contextFactory;
      }
  
      public int SafeRemove(string name, int barId)
      {
          using var context = _contextFactory.CreateDbContext();
          var itemToRemove = context.Foos.SingleOrDefault(foo =&gt; foo.BarId == barId &amp;&amp; foo.Name == name);
  
          if (itemToRemove != null)
              context.Foos.Remove(itemToRemove);
          
          return context.SaveChanges();
      }
  }
  </code></pre>
  <p>DependencyInjection registrations:</p>
  <pre><code>Host = Microsoft.Extensions.Hosting.Host.CreateDefaultBuilder()
         .ConfigureServices((_, services) =&gt; 
         {
             services
                 .AddDbContextFactory&lt;MyDbContext&gt;(options =&gt; options.UseSqlServer(configuration.GetConnectionString(&quot;MyDbContext&quot;)))
                 .AddSingleton&lt;SafeRemover&gt;();
         }).Build();
  </code></pre>
  <p>I want to unit test that this method removes or not certain entities from the given set in database context.</p>
  <h3>Attempt 1 InMemoryDatabase + mocks:</h3>
  <pre><code>private static readonly object[] _safeRemoveSource = 
  {
      new TestCaseData(&quot;Foo1&quot;, 1, new List&lt;Foo&gt;()).SetName(&quot;SafeRemove_FooExists_FooRemoved&quot;),
      new TestCaseData(&quot;Foo2&quot;, 1, new List&lt;Foo&gt; { new Foo { Name = &quot;Foo1&quot;, BarId = 1 } }).SetName(&quot;SafeRemove_FooWithDifferentNameExists_FooNotRemoved&quot;),
      new TestCaseData(&quot;Foo1&quot;, 2, new List&lt;Foo&gt; { new Foo { Name = &quot;Foo1&quot;, BarId = 1 } }).SetName(&quot;SafeRemove_FooWithDifferentBarIdExists_FooNotRemoved&quot;),
  }    
  
  [TestCaseSource(nameof(_safeRemoveSource))]
  public void SafeRemoveTest(string name, int barId, IList&lt;Foo&gt; expectedFoos)
  {
      var options = new DbContextOptionsBuilder&lt;MyDbContext&gt;().UseInMemoryDatabase(Guid.NewGuid().ToString()).Options;  
  
      var contextMock = new Mock&lt;MyDbContext&gt;(options) {CallBase = true};
      contextMock.Setup(context =&gt; context.PreSaveActions());
  
      var contextFactoryMock = new Mock&lt;IDbContextFactory&lt;MyDbContext&gt;&gt;();
      contextFactoryMock.Setup(factory =&gt; factory.CreateDbContext()).Returns(contextMock.Object);
  
      var safeRemover = new SafeRemover(contextFactoryMock.Object);
      
      safeRemover.SafeRemove(name, barId);
      var actualFoos = contextMock.Object.Foos.ToList();
  
      Assert.AreEqual(expectedFoos.Count(), actualFoos.Count());
      for (var i = 0; i &lt; expectedFoos.Count(); i++)
          Assert.That(expectedFoos[i].Name.Equals(actualFoos[i].Name) &amp;&amp; expectedFoos[i].BarId == actualFoos[i].BarId);
  }
  </code></pre>
  <p>When I use the <code>InMemoryDatabase</code> I am unable to check the value of <code>contextMock.Object.Foos.ToList()</code> after invoking <code>saveRemover.SafeRemove(name, barId)</code> because the <code>contextMock.Object</code> is already disposed:</p>
  <blockquote>
  <p>System.ObjectDisposedException: Cannot access a disposed object. A common cause of this error is disposing a context that was resolved from dependency injection and then later trying to use the same context instance elsewhere in your application. This may occur is you are calling Dispose() on the context, or wrapping the context in a using statement. If you are using dependency injection, you should let the dependency injection container take care of disposing context instances. Object name: 'Context'.</p>
  </blockquote>
  <h3>Attempt 2 Mocked dbset and callbacks:</h3>
  <pre><code>private static readonly object[] _safeRemoveSource = 
  {
      new TestCaseData(&quot;Foo1&quot;, 1, new List&lt;Foo&gt;()).SetName(&quot;SafeRemove_FooExists_FooRemoved&quot;),
      new TestCaseData(&quot;Foo2&quot;, 1, new List&lt;Foo&gt; { new Foo { Name = &quot;Foo1&quot;, BarId = 1 } }).SetName(&quot;SafeRemove_FooWithDifferentNameExists_FooNotRemoved&quot;),
      new TestCaseData(&quot;Foo1&quot;, 2, new List&lt;Foo&gt; { new Foo { Name = &quot;Foo1&quot;, BarId = 1 } }).SetName(&quot;SafeRemove_FooWithDifferentBarIdExists_FooNotRemoved&quot;),
  }    
  
  [TestCaseSource(nameof(_safeRemoveSource))]
  public void SafeRemoveTest(string name, int barId, IList&lt;Foo&gt; expectedFoos)
  {
      var actualFoos = new List&lt;Foo&gt; { new Foo { Name = &quot;Foo1&quot;, BarId = 1 } };
      var options = new DbContextOptionsBuilder&lt;MyDbContext&gt;().UseInMemoryDatabase(Guid.NewGuid().ToString()).Options;  
  
      var foosMock = new Mock&lt;DbSet&lt;Foo&gt;&gt; {CallBase = true};
      foosMock.Setup(set =&gt; set.Remove(It.IsAny&lt;Foo&gt;())).Callback&lt;Foo&gt;(foo =&gt; actualFoos.Remove(foo));
  
      var contextMock = new Mock&lt;MyDbContext&gt;(options) {CallBase = true};
      contextMock.Setup(context =&gt; context.PreSaveActions());
      contextMock.Setup(context =&gt; context.Foos).Returns(foosMock.Object);
  
      var contextFactoryMock = new Mock&lt;IDbContextFactory&lt;MyDbContext&gt;&gt;();
      contextFactoryMock.Setup(factory =&gt; factory.CreateDbContext()).Returns(contextMock.Object);
  
      var safeRemover = new SafeRemover(contextFactoryMock.Object);
      
      safeRemover.SafeRemove(name, barId);
  
      Assert.AreEqual(expectedFoos.Count(), actualFoos.Count());
      for (var i = 0; i &lt; expectedFoos.Count(); i++)
          Assert.That(expectedFoos[i].Name.Equals(actualFoos[i].Name) &amp;&amp; expectedFoos[i].BarId == actualFoos[i].BarId);
  }
  </code></pre>
  <p>Everything seems to work as expected instead of one thing... I'm getting NotSupportedException on <code>SingleOrDefault</code> method in above configuration of mocks:</p>
  <blockquote>
  <p>System.NotSupportedException : Specified method is not supported.</p>
  </blockquote>
  <h3>Attempt 3 (successfull)</h3>
  <p>I went back to the attempt 1 and removed <code>using</code> clause. Now it seems to work as expected, but am I safe to do so? Would <a href="https://www.google.com/search?client=firefox-b-d&amp;q=nuget+dependency+injection+.net+6" rel="nofollow noreferrer">DI container</a> be smart enough to leave it entirely for him?
  I can't find anything about that in the docs and I'm not that good at profiling to check it comprehensively.</p>
  <h1>@Edit:</h1>
  <p>I've used InMemoryDatabase with derivered <code>TestMyDbContext</code> class. Still without success. I've got <code>ObjectDisposedException</code> on the following line: <code>var actualFoos = context.Foos.ToList();</code></p>
  <p>TestMyDbContext:</p>
  <pre><code>public class TestMyDbContext : MyDbContext
  {
      public override void PreSaveActions() {}
  }
  </code></pre>
  <p>Unit test:</p>
  <pre><code>private static readonly object[] _safeRemoveSource = 
  {
      new TestCaseData(&quot;Foo1&quot;, 1, new List&lt;Foo&gt;()).SetName(&quot;SafeRemove_FooExists_FooRemoved&quot;),
      new TestCaseData(&quot;Foo2&quot;, 1, new List&lt;Foo&gt; { new Foo { Name = &quot;Foo1&quot;, BarId = 1 } }).SetName(&quot;SafeRemove_FooWithDifferentNameExists_FooNotRemoved&quot;),
      new TestCaseData(&quot;Foo1&quot;, 2, new List&lt;Foo&gt; { new Foo { Name = &quot;Foo1&quot;, BarId = 1 } }).SetName(&quot;SafeRemove_FooWithDifferentBarIdExists_FooNotRemoved&quot;),
  }    
  
  [TestCaseSource(nameof(_safeRemoveSource))]
  public void SafeRemoveTest(string name, int barId, IList&lt;Foo&gt; expectedFoos)
  {
      var initialFoos = new List&lt;Foo&gt; { new Foo { Name = &quot;Foo1&quot;, BarId = 1 } };
      var options = new DbContextOptionsBuilder&lt;MyDbContext&gt;().UseInMemoryDatabase(Guid.NewGuid().ToString()).Options;  
  
      using var context = new TestMyDbContext(options);
      context.Foos.AddRange(actualFoos);
      context.SaveChanges();
  
      var contextFactoryMock = new Mock&lt;IDbContextFactory&lt;MyDbContext&gt;&gt;();
      contextFactoryMock.Setup(factory =&gt; factory.CreateDbContext()).Returns(context);
  
      var safeRemover = new SafeRemover(contextFactoryMock.Object);
      
      safeRemover.SafeRemove(name, barId);
      var actualFoos = context.Foos.ToList();
  
      Assert.AreEqual(expectedFoos.Count(), actualFoos.Count());
      for (var i = 0; i &lt; expectedFoos.Count(); i++)
          Assert.That(expectedFoos[i].Name.Equals(actualFoos[i].Name) &amp;&amp; expectedFoos[i].BarId == actualFoos[i].BarId);
  }
  </code></pre>