2

I'm trying to write unit tests but I'm having trouble figuring out how to delegate functions.

The application is an MVC application and the unit tests depend on moc data (they do not use the database).

We made a change to one of our services, and now the unit tests that test that service are failing. The adjustment I need to make to the unit tests don't seem to work, and this is what I need help with.

First of all, here's how it worked before the change:

The function in the service to be tested:

public Project GetProject(int projectId)
{    
    return _context.Projects.Find(projectId);    
}

Substituting the delegate function in our unit tests:

protected override void Given()
{
    GetMockFor<IRiskAliveContext>()    
    .Setup(ctx => ctx.Projects.Find(1))    
    .Returns(GetTestProject(1));
}

So essentially, we are say that whenever the service calls context.Projects.Find(1), return the mock project from GetTestProject(1).

This worked fine until we made our change:

public Project GetProject(int projectId)
{
    return _context.Projects.Include("Report").FirstOrDefault(p => p.ProjectId == projectId);    
}

It doesn't seem we can substitute a delegate function to calls to context.Projects.Include("report").FirstOrDefault(...), at least not in the same way as context.Project.Find(...). When I try to substitute the function as follows, I get a NotSupportedException

protected override void Given()
{    
    GetMockFor<IRiskAliveContext>()    
    .Setup(ctx => ctx.Projects.Include("Report").FirstOrDefault(p => p.ProjectId == 1))
    .Returns(GetTestProject(1));
}

Is there a different way to substitute a delegate function when the call is to ...Include(...).FirstOrDefault(...)?

Nkosi
  • 235,767
  • 35
  • 427
  • 472
gib65
  • 141
  • 3
  • 16
  • 1
    You are trying to mock extension methods, which is not available in the mocking framework being used. – Nkosi Oct 02 '17 at 16:16
  • 2
    Please add some context - Which language (c#?)? Also, what frameworks are you using - for example, the `GetMockFor` is from where? Which packages do you have installed? – LightCC Oct 02 '17 at 16:17
  • The question in its current state is unclear as it is incomplete. Read [ask] and then provide a [mcve] that can be used to better understand your problem. – Nkosi Oct 02 '17 at 16:27
  • 1
    I think you don't need to write unit tests for `DbContext`, because you end up with testing your mocks. Instead suggest to use In-Memory database provider (in case you are using .NET Core) or use SQLLite in memory mode. For simple test cases where no complex `where` conditions suggest to use integration tests with actual database. With approaches above you will be able to "refactor" queries without re-writing tests or add some conditions only by adding test cases – Fabio Oct 03 '17 at 12:09

1 Answers1

0

For this sort of method, I like to mock the collection (ctx.Projects in this case) and then add a variety of data to that collection to check that the correct filters are applied. For example, in your case, I would add the other projects that have different ProjectIds and confirm that only the correct project is returned as this sort of test will provide a lot more value and you should be able to mock this more easily.

I won't go into the details of how to mock the DbSet or Include as these have been answered in other questions. These questions should be a good starting point:

How to add an item to a Mock DbSet (using Moq)

Moqing Enity Framework 6 .Include() using DbSet<>

TomDoesCode
  • 3,580
  • 2
  • 18
  • 34