Entity Framework Testing that SaveChanges is present and called in the correct place in the method

I have a class like the following that I want unit test:

public class AddUserCommand { IDbContext dbContext; public AddUserCommand(IDbContext context) { dbContext = context; } public void Execute() { dbContext.Users.Add(new User()); dbContext.SaveChanges(); } } 

Ultimately, I need to check if the Execute method saves the new user to the database when using a real sql database connection. But for my unit tests, I obviously want to use some kind of layout. In my tests, I can make an IDbContext layout that mimics the behavior, and it all works. I can verify that the layout context contains the new user after running the Execute method.

My problem is that when using the layout context, the test will pass unless I call the SaveChanges method. This is because the layout context does not require the creation of an SQL query to actually save the data. It is "saved" without calling SaveChanges, because the Users collection is persistent storage.

To check that SaveChanges is being called, many online sources (for example: http://msdn.microsoft.com/en-us/library/ff714955.aspx and http://msdn.microsoft.com/en-gb/data/ dn314431.aspx ) let's say add something like this to the context layout:

 public class MockDbContext : IDbContext { boolean saved; public void SaveChanges { saved = true; } } 

And then check if the saved variable is saved after calling the Execute method. However, what I am missing in this approach is that such a test will pass if this method performed:

 public void Execute() { dbContext.SaveChanges(); dbContext.Users.Add(new User()); } 

Which, of course, will not save any changes, since this is done too early. I find that mocking frameworks like RhinoMocks allow you to check the order of method calls in the layout context, but I also read that this is not a good practice (you should check the result, not the implementation thumbnails).

The problem is that the context layout does not exactly replicate what a real DbContext will do.

So my question is: is there a standard way to falsify the structure of DbContext entities in such a way that any additions or deletions of objects are transferred only to the layout when SaveChanges is called? Or is this not what is usually tested?

+7
c # unit-testing entity-framework mocking
source share
1 answer

You must do this using Moq :

 // Counters to verify call order int callCount = 0; int addUser = 0; int saveChanges = 0; // use Moq to create a mock IDbContext. var mockContext = new Mock<IDbContext>(); // Register callbacks for the mocked methods to increment our counters. mockContext.Setup(x => x.Users.Add(It.IsAny<User>())).Callback(() => addUser = callCount++); mockContext.Setup(x => x.SaveChanges()).Callback(() => saveChanges = callCount++); // Create the command, providing it the mocked IDbContext and execute it var command = new AddUserCommand(mockContext.Object); command.Execute(); // Check that each method was only called once. mockContext.Verify(x => x.Users.Add(It.IsAny<User>()), Times.Once()); mockContext.Verify(x => x.SaveChanges(), Times.Once()); // check the counters to confirm the call order. Assert.AreEqual(0, addUser); Assert.AreEqual(1, saveChanges); 

Following the comments on this answer, it seems like some people miss the unit test point and the purpose of using abstractions inside your code.

What you are doing here is checking the behavior of AddUserCommand , and that’s all - you confirm that the AddUserCommand class adds the user and saves the changes in context.

The reason for using the IDbContext interface is that you can isolate the AddUserCommand class without having a database in a known state. You do not need to check the implementation of the real DbContext , because it must have its own unit tests, which also cover it.

You can also create an integration test in which you would use a real DbContext and confirm that the record goes to the database, but this is not what the unit test does.

+13
source share

All Articles