title: Mock DbContext SaveChanges() method does not return any values
body: <p>I was wondering if anyone knew of a way to cause <code>SaveChanges()</code> to return a value other than 0 when mocking a <code>DbContext</code> using Moq. I frequently use <code>SaveChanges()</code> in my code to throw errors if the number of items changes Saved or UnSaved is less than or greater than the expected number of changes.</p>
  
  <p>In my experience using Moq, it doesn't look like <code>DbContext.SaveChanges()</code> will ever do anything if you aren't making calls to the database.</p>
  
  <p><strong>Update 9/8/2016</strong></p>
  
  <p>Suggestions from Jeroen Heier and Nkosi have helped provide a solution. I should have dug deeper into Mock and realized that <code>SaveChanges()</code> was a virtual (duh!). For reference I'll add the code below to demo what I'm doing. One thing to note is that you need to define a callback to save changes if your business logic depends on the number of items that are saved to the database <strong><code>DbContext.Setup().Callback(() =&gt; { /* do something */})</code></strong>. Using the callback you can keep track of the expected number of times save changes is called and Assert them in your test.</p>
  
  <p><strong>"SavePost" Method in the PostService class</strong></p>
  
  <pre><code>public PostViewModel SavePost(PostViewModel currentPost, bool publishPost)
  {
      //_context.Configuration.ProxyCreationEnabled = false;
  
      JustBlogContext currentContext = (JustBlogContext)_Context;
      Post newPost = new Post();
      List&lt;Tag&gt; postTags = new List&lt;Tag&gt;();
      DateTime currentDateTime = DateTime.UtcNow;
      bool saveSuccess = false;
  
      if (currentPost != null)
      {
          //Post
          newPost = new Post()
          {
              Category = currentPost.Category.Id.Value,
              Description = currentPost.Description,
              ShortDescription = currentPost.ShortDescription,
              Title = currentPost.Title,
              UrlSlug = currentPost.UrlSlug,
              Published = currentPost.Published == true || publishPost == true ? true : false,
              Meta = currentPost.Meta == "" || currentPost.Meta == null ? "No meta data" : currentPost.Meta,
              PostedOn = currentPost.PostedOn,
              Modified = currentDateTime
          };
  
          //Tags
          foreach (Tag currentTag in currentPost?.Tags)
          {
              postTags.Add(new Tag()
              {
                  Description = currentTag.Description,
                  Id = currentTag.Id,
                  Name = currentTag.Name,
                  UrlSlug = currentTag.UrlSlug
              });
          }
  
          if (currentPost.PostedOn == null &amp;&amp; publishPost)
          {
              newPost.PostedOn = currentDateTime;
          }
  
          /**
           * Note that you must track all entities
           * from the Post side of the Post - PostTagMap - Tag database schema.
           * If you incorrectly track entites you will add new tags as opposed to
           * maintaining the many-to-many relationship.
           **/
          if (currentPost?.Id == null)
          {
              //Add a new post
              //Attach tags from the database to post
              foreach (Tag clientTag in postTags)
              {
                  if (currentContext.Entry(clientTag).State == EntityState.Detached)
                  {
                      currentContext.Tags.Attach(clientTag);
                  }
              }
  
              newPost.Tags = postTags;
              currentContext.Posts.Add(newPost);
              saveSuccess = currentContext.SaveChanges() &gt; 0 ? true : false;
          }
          else
          {
              //Modify and existing post.
              bool tagsModified = false;
              newPost.Id = currentPost.Id.Value;
              currentContext.Posts.Attach(newPost);
              currentContext.Entry(newPost).State = EntityState.Modified;
  
              saveSuccess = currentContext.SaveChanges() &gt; 0 ? true : false;
              List&lt;Tag&gt; dataTags = currentContext.Posts.Include(post =&gt; post.Tags).FirstOrDefault(p =&gt; p.Id == newPost.Id).Tags.ToList();
  
              //Remove old tags
              foreach (Tag tag in dataTags)
              {
                  if (!postTags.Select(p =&gt; p.Id).ToList().Contains(tag.Id))
                  {
                      tagsModified = true;
                      newPost.Tags.Remove(tag);
                  }
              }
  
              if (postTags.Count() &gt; 0)
              {
                  //Add new tags
                  foreach (Tag clientTag in postTags)
                  {
                      //Attach each tag because it comes from the client, not the database
                      if (!dataTags.Select(p =&gt; p.Id).ToList().Contains(clientTag.Id))
                      {
                          currentContext.Tags.Attach(clientTag);
                      }
  
                      if (!dataTags.Select(p =&gt; p.Id).ToList().Contains(clientTag.Id))
                      {
                          tagsModified = true;
                          newPost.Tags.Add(currentContext.Tags.Find(clientTag.Id));
                      }
                  }
  
                  //Only save changes if we modified the tags
                  if (tagsModified)
                  {
                      saveSuccess = currentContext.SaveChanges() &gt; 0 ? true : false;
                  }
              }
          }
      }
  
      if (saveSuccess != false)
      {
          return loadEditedPost(currentContext, newPost);
      }
      else
      {
          throw new JustBlogException($"Error saving changes to {newPost.Title}");
      }
  }
  </code></pre>
  
  <p><strong>"SavePost_New_Post_Test" Test Method in PostService_Test.cs</strong></p>
  
  <pre><code>/// &lt;summary&gt;
  /// Test saving a new post
  /// &lt;/summary&gt;
  [TestMethod]
  public void SavePost_New_Post_Test()
  {
      //Arrange
      var postSet_Mock = new Mock&lt;DbSet&lt;Post&gt;&gt;();
  
      var justBlogContext_Mock = new Mock&lt;JustBlogContext&gt;();
      justBlogContext_Mock.Setup(m =&gt; m.Posts).Returns(postSet_Mock.Object);
  
      IPostService postService = new PostService(justBlogContext_Mock.Object);
  
      // setup Test
      CategoryViewModel newCategory = new CategoryViewModel()
      {
          Description = "Category Description",
          Id = 0,
          Modified = new DateTime(),
          Name = "Name",
          PostCount = 0,
          Posts = new List&lt;Post&gt;(),
          UrlSlug = "Category Url Slug"
      };
  
      Tag newTag = new Tag()
      {
          Description = "Tag Description",
          Id = 1,
          Modified = new DateTime(),
          Name = "Tag Name",
          Posts = new List&lt;Post&gt;(),
          UrlSlug = "Url Slug"
      };
  
      Tag newTag2 = new Tag()
      {
          Description = "Tag Description 2",
          Id = 2,
          Modified = new DateTime(),
          Name = "Tag Name 2",
          Posts = new List&lt;Post&gt;(),
          UrlSlug = "UrlSlug2"
      };
  
      List&lt;Tag&gt; tags = new List&lt;Tag&gt;();
  
      tags.Add(newTag);
      tags.Add(newTag2);
  
      // setup new post
      PostViewModel newPost = new PostViewModel()
      {
          Category = newCategory,
          Description = "Test Descritpion",
          Meta = "Meta text",
          Modified = new DateTime(),
          Published = false,
          PostedOn = null,
          ShortDescription = "Short Description",
          Title = "TestTitle",
          UrlSlug = "TestUrlSlug",
          Tags = tags,
          Id = null
      };
  
      // counters to verify call order
      int addPostCount = 0;
      int addTagAttachCount = 0;
      int saveChangesCount = 0;
      int totalActionCount = 0;
  
      // Register callbacks to keep track of actions that have occured
      justBlogContext_Mock.Setup(x =&gt; x.Posts.Add(It.IsAny&lt;Post&gt;())).Callback(() =&gt;
      {
          addPostCount++;
          totalActionCount++;
      });
  
      justBlogContext_Mock.Setup(x =&gt; x.SaveChanges()).Callback(() =&gt;
      {
          saveChangesCount++;
          totalActionCount++;
      });
  
      justBlogContext_Mock.Setup(x =&gt; x.SaveChanges()).Returns(1);
  
      justBlogContext_Mock.Setup(x =&gt; x.Tags.Attach(It.IsAny&lt;Tag&gt;())).Callback(() =&gt;
      {
          addTagAttachCount++;
          totalActionCount++;
      });          
  
      // Act
      postService.SavePost(newPost, false);
      // Assert
      justBlogContext_Mock.Verify(m =&gt; m.SaveChanges(), Times.AtLeastOnce());
      Assert.IsTrue(addPostCount == 1);
      Assert.IsTrue(addTagAttachCount == 2);
      Assert.IsTrue(totalActionCount == 4);
  }
  </code></pre>