4

I have a method like this:

private void CreateTaskFromModel(ForgotPasswordViewModel fpModel)
{
    var message = _dbContext.Create<Message>();

    message.MessageType = "TASK".PadLeft(10);
    message.Assigned_User_K = fpModel.SendPasswordRequestTo.Trim();
    message.Assigned_Date = DateTime.Today;
    message.Source_User_K = string.Empty;
    message.Title_Focus = "Request Web Password";

    _dbContext.Messages.Add(message);
}

So I was able to mock the Create method like this:

Message msg = new Message();
IMyDbContext fakeDbContext = NSubstitute.Substitute.For<IMyDbContext>();

fakeDbContext.Create<Message>().Returns(msg);

but notice the last line it still has this code, I don't know how to mock this one?

_dbContext.Messages.Add(message);

I am using NSubstittue

  • If you work with just DbContext you can implement mocking (with NSubstitute) using this framework outlined in [Testing with your own test doubles (EF6 onwards)](https://msdn.microsoft.com/en-us/data/dn314431.aspx). I created a wrapper around it and posted it to [GitHub](https://github.com/IgorWolbers/DbContextMockForUnitTests) to make it a little simpler to use/call. Again, for this to work just inject DbContext instead of the derived type you implement and then use the generic `Set` method to call your models on the context. – Igor Jun 16 '16 at 18:07
  • @Igor when it gets to _dbContext.Messages.Add(message); it crashes because .Messages is null ... can you help with that? –  Jun 16 '16 at 18:09
  • 1
    You've mocked the `IMyDbContext ` but you haven't mocked what it suppose to return for `IMyDbContext.Messages` hence it's null. You will also have to mock the `Add` method as well. – Nkosi Jun 16 '16 at 18:12
  • @Nkosi Yes I know. That's the syntax and part that I do NOT know how to write it and asking the question. Can you show me how to do that part? I mocked it as much as I know how to . –  Jun 16 '16 at 18:18
  • Are you CodeFirst or DatabaseFirst ? If you are DatabaseFirst, it is possible to create a mock context that instanciates a MetadataWorkspace object, that is the deserialized version of the edmx. You should be able to parse metadata and process Identity keys and FixUp operations, within the SaveChanges() method, using reflection. EF7 will implement In-Memory repositories. For previous versions, the most difficult part is to mock FixUp. In my case, it gave good results. But it was 3 days of work. – Rénald Jun 16 '16 at 18:38

1 Answers1

3

Messages is of type DbSet<Message>. So you need to create a fake/substitute instance of DbSet<Message> and have that me returned by _dbContext.Messages.

Message msg = new Message();
IMyDbContext fakeDbContext = NSubstitute.Substitute.For<IMyDbContext>();

var messagesSet = NSubstitute.Substitute.For<DbSet<Message>>();
fakeDbContext.Create<Message>().Returns(msg);
fakeDbContext.Messages.Returns(messagesSet);

You are also interested in seeing if Add was called. You can do this in your Asserts.

messagesSet.Received().Add(NSubstitute.Any<Message>());

or if you want to test if the same instance was added from your create

messagesSet.Received().Add(msg); // message created earlier in your test
Igor
  • 60,821
  • 10
  • 100
  • 175
  • Do I also need to "mock" the "Add" method? in Messages.Add ? Can you show me how please? –  Jun 16 '16 at 18:20
  • 1
    @KSNoob - No, you don't. Unless it returns something that you then reuse in your code like Create there is no reason to mock it. With NSubstitute you can use the above mentioned code to see if Add was called since that is what you are interested in. – Igor Jun 16 '16 at 18:21
  • Thank you so much for help. I was stuck . :) –  Jun 16 '16 at 18:23
  • Added entities are set with a Identity property, how do you mock it ? – Rénald Jun 16 '16 at 18:46