【问题标题】:XUnit Test Error: A test class may only define a single public constructorXUnit 测试错误:一个测试类只能定义一个公共构造函数
【发布时间】:2020-05-20 23:48:31
【问题描述】:

我有一个 XUnit 项目,它引用和测试另一个项目的 API 端点方法。但是,当我运行测试时,出现以下错误:

A test class may only define a single public constructor.

无法找到有关此问题可能意味着什么的太多信息,但我将在下面提供代码示例。任何帮助是极大的赞赏。

APIControllerTest.cs

using System;
using System.Collections.Generic;
using AppointmentAPI.Controllers;
using AppointmentAPI.Appt_Models;
using Microsoft.EntityFrameworkCore;
using Xunit;

namespace AppointmentAPITests
{
    public class APIControllerTests
    {

        #region Seeding
        protected APIControllerTests(DbContextOptions<ApptSystemContext> contextOptions)
        {
            ContextOptions = contextOptions;

            Seed();
        }

        protected DbContextOptions<ApptSystemContext> ContextOptions { get; }

        private void Seed()
        {
            using (var context = new ApptSystemContext(ContextOptions))
            {
                // this ensures that a fresh in-memory db is used for each test
                context.Database.EnsureDeleted();
                context.Database.EnsureCreated();

                var one = context.AppointmentSlots.Add(new AppointmentSlots
                {
                    SlotId = 1,
                    Date = Convert.ToDateTime("2020-03-31 00:00:00.000"),
                    Time = TimeSpan.Parse("12:00:00.0000000"),
                    ApptJson = "{'fname':'Billy','lname':'Joel','age':70,'caseWorker':'Donna', 'appStatus':'finished'}",
                    Timestamp = Convert.ToDateTime("2020-02-24 12:00:00.000")
                });

                var two = context.AppointmentSlots.Add(new AppointmentSlots
                {
                    SlotId = 2,
                    Date = Convert.ToDateTime("2020-02-14 00:00:00.000"),
                    Time = TimeSpan.Parse("10:30:00.0000000"),
                    ApptJson = "{'fname':'Nick','lname':'Nicholas','age':25,'caseWorker':'Brenda', 'appStatus':'finished'}",
                    Timestamp = Convert.ToDateTime("2020-02-10 11:38:00.000")
                });

                var three = context.AppointmentSlots.Add(new AppointmentSlots
                {
                    SlotId = 3,
                    Date = Convert.ToDateTime("2020-01-02 00:00:00.000"),
                    Time = TimeSpan.Parse("03:45:00.0000000"),
                    ApptJson = "{'fname':'Macey','lname':'Johnson','age':43,'caseWorker':'Donna', 'appStatus':'unfinished'}",
                    Timestamp = Convert.ToDateTime("2020-01-01 09:34:00.000")
                });

                var four = context.AppointmentSlots.Add(new AppointmentSlots
                {
                    SlotId = 4,
                    Date = Convert.ToDateTime("2020-05-17 00:00:00.000"),
                    Time = TimeSpan.Parse("01:15:00.0000000"),
                    ApptJson = "{'fname':'James','lname':'Wally','age':35,'caseWorker':'Brad', 'appStatus':'finished'}",
                    Timestamp = Convert.ToDateTime("2020-04-28 02:03:00.000")
                });

                var five = context.AppointmentSlots.Add(new AppointmentSlots
                {
                    SlotId = 5,
                    Date = Convert.ToDateTime("2019-11-23 00:00:00.000"),
                    Time = TimeSpan.Parse("12:45:00.0000000"),
                    ApptJson = "{'fname':'Emily','lname':'Carlton','age':62,'caseWorker':'Brenda', 'appStatus':'unfinished'}",
                    Timestamp = Convert.ToDateTime("2019-11-19 11:07:00.000")
                });

                var six = context.AppointmentSlots.Add(new AppointmentSlots
                {
                    SlotId = 6,
                    Date = Convert.ToDateTime("2020-07-24 00:00:00.000"),
                    Time = TimeSpan.Parse("10:00:00.0000000"),
                    ApptJson = "{'fname':'Michael','lname':'Smith','age':52,'caseWorker':'Donna', 'appStatus':'finished'}",
                    Timestamp = Convert.ToDateTime("2020-06-25 09:34:00.000")
                });

                var seven = context.AppointmentSlots.Add(new AppointmentSlots
                {
                    SlotId = 7,
                    Date = Convert.ToDateTime("2020-05-19 00:00:00.000"),
                    Time = TimeSpan.Parse("08:45:00.0000000"),
                    ApptJson = null,
                    Timestamp = null
                });

                var eight = context.AppointmentSlots.Add(new AppointmentSlots
                {
                    SlotId = 8,
                    Date = Convert.ToDateTime("2020-06-05 00:00:00.000"),
                    Time = TimeSpan.Parse("02:45:00.0000000"),
                    ApptJson = null,
                    Timestamp = null
                });

                var nine = context.AppointmentSlots.Add(new AppointmentSlots
                {
                    SlotId = 9,
                    Date = DateTime.Now.AddMonths(2),
                    Time = TimeSpan.Parse("02:45:00.0000000"),
                    ApptJson = null,
                    Timestamp = null
                });

                context.AddRange(one, two, three, four, five, six, seven, eight, nine);

                context.SaveChanges();
            }
        }
        #endregion

        #region AssignAppts
        [Fact]
        public void TestAssignAppts()
        {
            using (var context = new ApptSystemContext(ContextOptions))
            {
                var controller = new apptController(context);

                // Arrange
                var request = new AppointmentAPI.Appt_Models.AppointmentSlots
                {
                    SlotId = 7,
                    ApptJson = "{'fname':'Emily','lname':'Carlton','age':62,'caseWorker':'Brenda', 'appStatus':'unfinished'}",
                    Timestamp = Convert.ToDateTime("2020-06-25 09:34:00.000")
                };

                string expectedResponse = "Task Executed\n";

                // Act
                var response = controller.assignAppt(request);

                // Assert
                Assert.Equal(response, expectedResponse);
            }
        }
        #endregion
    }
}

sqliteInMemoryAPIController.cs

using System;
using System.Collections.Generic;
using System.Data.Common;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Infrastructure;
using AppointmentAPI.Appt_Models;

namespace AppointmentAPITests
{
    #region SqliteInMemory
    class SqliteInMemoryAPIController : APIControllerTests, IDisposable
    {
        private readonly DbConnection _connection;

        private SqliteInMemoryAPIController()
            : base(
                 new DbContextOptionsBuilder<ApptSystemContext>()
                     .UseSqlite(CreateInMemoryDatabase())
                     .Options)
        {
            _connection = RelationalOptionsExtension.Extract(ContextOptions).Connection;

        }

        private static DbConnection CreateInMemoryDatabase()
        {
            var connection = new SqliteConnection("Filename:=memory:");

            connection.Open();

            return connection;
        }

        public void Dispose() => _connection.Dispose();
    }
    #endregion
}

【问题讨论】:

  • 注意:a single **public** constructor。你的构造函数是private
  • 我将 SqliteInMemoryAPIController 更改为 public,但我仍然遇到同样的错误
  • 删除测试类APIControllerTests的构造函数的参数。您需要在构造函数中实例化所需的上下文选项。在 XUnit 中,测试类构造函数是所有测试的入口点。

标签: c# visual-studio api unit-testing xunit


【解决方案1】:

构造函数必须是public,在你的例子中是protected

public APIControllerTests(DbContextOptions<ApptSystemContext> contextOptions)
{
    ContextOptions = contextOptions;
    
    Seed();
}

【讨论】:

    【解决方案2】:

    我在搜索相同的答案后找到了您的问题。

    您似乎也在关注本指南:https://github.com/dotnet/EntityFramework.Docs/blob/master/samples/core/Miscellaneous/Testing/ItemsWebApi/Tests/ItemsControllerTest.cs

    public class APIControllerTests
    

    应该是

    public abstract class APIControllerTests
    

    【讨论】:

    • 很遗憾我不再从事这个项目,但感谢您对未来的洞察!
    • 在我的情况下,使课程抽象并不能解决它。当类是抽象类时,其中的测试不会显示在测试资源管理器中。
    猜你喜欢
    • 1970-01-01
    • 2017-03-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-05-04
    相关资源
    最近更新 更多