1

I have an Entity Framework DbContext, let's call it SomeEntities. Another member of my team who is no longer here wrote an extension method for SomeEntities that is now used all over our applications.

public static bool SaveWithAudit(this SomeEntities context, string activity, int userId)
{
    context.SaveChanges();
    logWhatHappened(userId);  //there's more here, doing this for brevity
}

I am working on unit tests for our service layer which interacts with the data context and have learned the hard way that I can't test static members with Moq. I was using Microsoft Fakes, but have learned the hard way that unit tests using Fakes don't show up in dotCover results. In my research, I have seen a few cases where people have wrapped or created their own stubs to deal with these situations, but I haven't found a specific example that makes sense for my scenario. So my question is: Is there a way that I can stub and/or set up a wrapper that allows me to mock this extension method for unit testing?

Community
  • 1
  • 1
AJ.
  • 16,368
  • 20
  • 95
  • 150

1 Answers1

1

SaveWithAudit method is a static method,so you cannot mock it (you can try to use commercial mocking framework).

However you can move logic from extension method to your context by wrapping SomeEntities into interface

public interface ISomeEntitiesContext
{
    int SaveChanges();

    bool SaveWithAudit(this SomeEntities context, string activity, int userId);
    // add other methods if required
}

Context should implement ISomeEntitiesContext as well as DbContext

public partial class SomeEntitiesContext : DbContext, ISomeEntitiesContext
{
    public bool SaveWithAudit(this SomeEntities context, string activity, int userId)
    {
        this.SaveChanges();
        logWhatHappened(userId);
    }
}

In this way you will be able to use ISomeEntitiesContext.SaveWithAudit method in your service layer, without mocking extension methods.

This solution violates Single Responsibility principle as now SomeEntitiesContext knows how to save entities as well as how to log audit messages. If you have IoC container, it might have interceptor capabilities. On our project all auditing is done with Castle Windsor interceptors, our code doesn't have nasty entries of log.LogMessage("...").

Community
  • 1
  • 1
Andrei Mihalciuc
  • 2,148
  • 16
  • 14