Can't Mock _db.Users for XUnit Testing in C# MVC App

Viewed 70

I have an MVC app and I'm trying to do Unit Testing and injecting all of the relevant code into the Testing app. This is the part of my actual app (called amaranth) that I'm currently testing for the Index() function (which returns a View) in a Controller called amaranth/Controllers/AdminController.cs:

using System;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using amaranth.Data;
using amaranth.Models.ViewModels;
using amaranth.Helpers;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using amaranth.Models;
using NBitcoin;
using Newtonsoft.Json.Linq;
using System.Collections.Generic;

namespace amaranth.Controllers
{
    [Authorize(Roles = "Admin")]
    public class AdminController : Controller
    {
        private ApplicationDbContext _db;
        private UserManager<IdentityUser> _manager;
        private BitcoinHelper _btcHelper;

        public AdminController(ApplicationDbContext ctx, UserManager<IdentityUser> manager, BitcoinHelper bitcoinHelper) : base()
        {
            _db = ctx;
            _manager = manager;
            _btcHelper = bitcoinHelper;
        }

        public IActionResult Index()
        {
            var users = _db.Users
                .OrderBy(p => p.Id)
                .ToList();

            return View(users);
        }

I want to test Index(). So I have a parallel project amaranth.Tests in the same directory as amaranth. I constructed the following test in amaranth.Tests/Controllers/AdminControllerTest.cs:

using Moq;
using amaranth.Data;
using Microsoft.AspNetCore.Identity;
using Xunit;
using Microsoft.EntityFrameworkCore;

namespace amaranth.Tests.Controllers
{
    public class AdminControllerTest
    {
        private Mock<ApplicationDbContext> _db = new Mock<ApplicationDbContext>();
        private Mock<UserManager<IdentityUser>> _manager = new Mock<UserManager<IdentityUser>>();

        [Fact]
        public void Test1()
        {
            var options = new DbContextOptionsBuilder<Users>()
                .UseInMemoryDatabase(databaseName: "amaranth_test_dbone")
                .Options;

            using (var context = new UserContext(options))
            {
                context.Users.Add(new User { UserName = "example@gmail.com", NormalizedUserName = "EXAMPLE@GMAIL.COM", Email = "EXAMPLE@GMAIL.COM" });
                context.SaveChanges();
            }

            using (var context = new UserContext(options))
            {
                var users = _db.Users
                    .OrderBy(p => p.Id)
                    .ToList();
                Assert.NotEmpty(users);
            }
        }
    }
}

This test is just supposed to see if the users entry contains any actual entries which it should because I "Mocked" one called "example@gmail.com." The compiler throws the error 'DbContextOptionsBuilder<Users>' does not contain a definition for 'UseInMemoryDatabase' and no accessible extension method 'UseInMemoryDatabase' accepting a first argument of type 'DbContextOptionsBuilder<Users>', could be found (are you missing a using directive or an assembly reference?) on UseInMemoryDatabase and can't find Users or UserContext. So what am I doing wrong?

1 Answers

You need to add the Microsoft.EntityFrameworkCore.InMemory nuget package.

Also, since you create the in memory database you don't need the mock _db, which will also not going to work, because you mock interfaces, not the actual classes.

For the UserManager, since it's not an interface and you don't control it, see here how to mock it: How to mock UserManager in .Net Core testing?

Related