I'm writing a bunch of unit tests for my ASP.NET MVC app using Entity Framework (against a SQL Server database).
I'm using Rowan Miller's excellent Nuget packages "EntityFramework.Testing" and "EntityFramework.Testing.Moq" to allow me to unit test EF code (without actually having a real SQL Server database around).
This is my NUnit 3.5 test fixture (in reality, it has a lot more tests - but it's just to show how things are set up):
[TestFixture]
public class ContactsUseCaseTests : MyUnitTestBase
{
private Mock<MyModel> _mockDbContext;
private MockDbSet<Contact> _mockDbSetContact;
private IContactsUseCase _usecase;
[SetUp]
public void InitializeTest()
{
SetupTestData();
_usecase = new ContactsUseCase(_mockDbContext.Object);
}
[Test]
public void TestSaveEntryNotNewButNotFound()
{
// Arrange
Contact contact = new Contact { ContactId = 99, FirstName = "Leo", LastName = "Miller" };
// Act
_usecase.SaveContact(contact, false);
// Assert
_mockDbSetContact.Verify(x => x.Add(It.IsAny<Contact>()), Times.Once);
_mockDbContext.Verify(x => x.SaveChanges(), Times.Once);
}
private void SetupTestData()
{
var contacts = new List<Contact>();
contacts.Add(new Contact { ContactId = 12, FirstName = "Joe", LastName = "Smith" });
contacts.Add(new Contact { ContactId = 17, FirstName = "Daniel", LastName = "Brown" });
contacts.Add(new Contact { ContactId = 19, FirstName = "Frank", LastName = "Singer" });
_mockDbSetContact = new MockDbSet<Contact>()
.SetupAddAndRemove()
.SetupSeedData(contacts)
.SetupLinq();
_mockDbContext = new Mock<MyModel>();
_mockDbContext.Setup(c => c.ContactList).Returns(_mockDbSetContactList.Object);
_mockDbContext.Setup(c => c.Contact).Returns(_mockDbSetContact.Object);
}
}
As you can see, in the [SetUp] method, I'm calling SetupTestData which is creating the Mock<MyModel> for mocking the entire DbContext, and it sets up a MockDbSet<Contact> to handle my contacts.
Most tests works just fine against this setup - until I came across the SaveContact method here:
public void SaveContact(Contact contactToSave, bool isNew) {
if (isNew) {
ModelContext.Contact.Add(contactToSave);
} else {
ModelContext.Entry(contactToSave).State = EntityState.Modified;
}
ModelContext.SaveChanges();
}
As you can see, if I'm trying to save a Contact that already exists, all I'm doing is setting it's State flag to Modified and letting EF handle all the rest.
Works great at runtime - but here in the test, it causes the test code to want to connect to the database - which I don't have at hand.
So what do I need to do additionally to make it possible to unit-test this line of code using my EF Mocking infrastructure? Can it be done at all?
ModelContext.Entry(contactToSave).State = EntityState.Modified;