XUnit Test Error: A test class may only define a single public constructor
Asked Answered
R

2

8

I have an XUnit project that references and tests an API endpoint method of another project. When I run the test however I get the following error:

A test class may only define a single public constructor.

Haven't been able to find much about what this issue might mean but I'll provide the code samples below. Any help is greatly appreciated.

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
}

Rollie answered 20/5, 2020 at 23:48 Comment(3)
NOTE: a single **public** constructor. Your constructor is privateMinny
I changed SqliteInMemoryAPIController to public but I still get the same errorRollie
Remove parameter for a constructor of test class APIControllerTests. You need to instantiate required context options in the constructor. In XUnit test class constructor is entry point of all tests.Lauritz
A
17

The constructor must be public, it is protected in your example:

public APIControllerTests(DbContextOptions<ApptSystemContext> contextOptions)
{
    ContextOptions = contextOptions;
    
    Seed();
}
Anesthesiology answered 3/11, 2020 at 16:59 Comment(0)
A
2

I found your question after searching for the same answer.

Looks like you were following this guide as well: https://github.com/dotnet/EntityFramework.Docs/blob/master/samples/core/Miscellaneous/Testing/ItemsWebApi/Tests/ItemsControllerTest.cs

public class APIControllerTests

is supposed to be

public abstract class APIControllerTests
Ardyce answered 14/6, 2020 at 22:15 Comment(2)
Unfortunately I'm no longer working on this project but thanks for the future insight!Rollie
making class abstact does not solve it in my case. When the class is abstract then the test in it are not shown in the test explorer.Jocelyn

© 2022 - 2024 — McMap. All rights reserved.