Muhammad Adeel Zahid
Muhammad Adeel Zahid

Reputation: 17794

Injecting DbContext in constructor of Web api 2 controller

I am creating a small proof of concept asp.net web api 2 service with entity framework code first. The controller's constructor looks like

public AccountController: ApiController
{
    private readonly DbContext context;
    public AccountController(DbContext _context){
        context = _context;
    }
    public AccountController(){context = new ApplicationContext();}
}

I need to unit test my controllers. How can I mock the DbContext class. Is there a simple way of doing this? I want to avoid all that repository pattern with lot of interfaces. Because it will be a way overkill for this prototype.

Upvotes: 4

Views: 1780

Answers (1)

govin
govin

Reputation: 6733

Its usually something like this if you use Nunit and Moq.

    [TestFixture]
    public class AccountControllerTest
    {
      private Mock<DbContext> mockContext;

      private AccountController sut;


      [SetUp]
      public void TestSetup()
      {
        mockContext = new Mock<DbContext>();
        var account = new Account() { Id = 123, Name = "Test Account" };
        mockContext.SetUp(x => x.GetAccountOnContext()).Returns(account);
        sut = new Controller(mockContext.Object) { Request = new HttpRequestMessage() };
        sut.Request.Properties.Add(HttpPropertyKeys.HttpConfigurationKey, new HttpConfiguration());
      }

      [Test]
      public void ControllerMethod_GetLogin_Test()
      {
        // assuming GetLogin calls GetAccount on DbContext()

        var response = sut.GetLogin(someAccount);
        Assert.AreEqual(HttpStatusCode.OK, response.StatusCode);
        mockContext.Verify();
      }
   }

You basically want to mock out your external dependencies and test just what the SUT (System Under Test) is supposed to do. I would also strongly encourage to look at Fakes instead of mocks. In general fakes result in less brittle tests.

So in this case, you could have a FakeDbContext() that you can pass to the tests. The FakeDbContext() will behave more like the actual DbContext() but will do all those operations in-memory, so that your tests don't have a dependency with a real database.

Depending on the database you use, you can also look at starting an embedded version of the real database as a part of your tests. Just have to make sure to do the necessary stopping and clean up of the test database records after the test run is complete in the TearDown() method.

Upvotes: 1

Related Questions