Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
3.4k views
in Technique[技术] by (71.8m points)

Can't run tests for a controller doing Entity Framework Core operations in xUnit

I can't run tests for a controller doing Entity Framework Core operations in xUnit. I am using in-memory database and the error I am getting is:

**A test class may only define a single public constructor.**

The test class is:

using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
using MyAppT.Controllers;
using MyAppT.Models;
using Xunit;

namespace TestingProject
{

    public class TestRegistration
    {
        #region Seeding
        protected TestRegistration(DbContextOptions<AppDbContext> contextOptions)
        {
            ContextOptions = contextOptions;
            Seed();
        }

        protected DbContextOptions<AppDbContext> ContextOptions { get; }

        private void Seed()
        {
            using (var context = new AppDbContext(ContextOptions))
            {
                context.Database.EnsureDeleted();
                context.Database.EnsureCreated();

                var one = new Register()
                {
                    Name = "Test One",
                    Age = 40
                };

                var two = new Register()
                {
                    Name = "Test Two",
                    Age = 50
                };

                var three = new Register()
                {
                    Name = "Test Three",
                    Age = 60
                };
                context.AddRange(one, two, three);
                context.SaveChanges();
            }
        }
        #endregion

        [Fact]
        public void Test_Create_GET_ReturnsViewResultNullModel()
        {
            using (var context = new AppDbContext(ContextOptions))
            {
                // Arrange
                var controller = new RegistrationController(context);

                // Act
                var result = controller.Create();

                // Assert
                var viewResult = Assert.IsType<ViewResult>(result);
                Assert.Null(viewResult.ViewData.Model);
            }
        }
    }
}

The controller that is doing EF core operations is:

using Microsoft.AspNetCore.Mvc;
using MyAppT.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace MyAppT.Controllers
{
    public class RegistrationController : Controller
    {
        private AppDbContext context;
        public RegistrationController(AppDbContext appDbContext)
        {
            context = appDbContext;
        }

        public IActionResult Create()
        {
            return View();
        }

        [HttpPost]
        public async Task<IActionResult> Create(Register register)
        {
            if (ModelState.IsValid)
            {
                context.Add(register);
                await context.SaveChangesAsync();

                return RedirectToAction("Read");
            }
            else
                return View();
        }
    }
}

The strange error while running the test shows up in Test Explorer - A test class may only define a single public constructor.

I could not find anything about it on stackoverflow. Please help in fixing it?


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Your constructor needs to be parameterless for this to work, unless you're using some DI framework within your testing project, which is something that you generally shouldn't be doing. Instead, try creating the DBContextOptions within the constructor and assigning it to your class variable. You can then use it when you seed the database, and when you test against it.

Try this instead. You will need to add the Microsoft.EntityFrameworkCore.InMemory package into your test project if you don't have this in there already.

public class TestRegistration
{
    #region Seeding
    public TestRegistration()
    {
        ContextOptions = new DbContextOptionsBuilder<AppDbContext>()
              .UseInMemoryDatabase(databaseName: "Test")
              .Options;
        Seed();
    }

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...