在内存数据库中使用 MS Tests 和 sqlite 进行 API 单元测试

问题描述 投票:0回答:1

我知道还有其他帖子也有类似的问题,但我找不到具体的答案,所以我在这里:D。我正在为我正在构建的 Dapper API 创建单元测试。该 API 是用 C# 构建的,并连接到生产中的 Postgres DB。 API 使用 DI 和 IDbConnectionFactory 向控制器提供连接字符串。为了测试 API,我创建了一个 MStest 项目来测试控制器。我一直在尝试在内存数据库中创建一个 sqlite 来模拟实际的数据库,以免依赖于外部依赖项,即我的 Postgres 数据库。

我已经成功地创建了数据库并用数据填充它,并验证了其中包含示例数据。但是当尝试将此 sqlite 连接字符串传递到我的控制器时,它说找不到表......请帮助:D

    //my controller
    using CrudApi.Models;
    using CrudApi.DbConnectionFactories;
    using Dapper;
    using Microsoft.AspNetCore.Mvc;
    using Npgsql;
    using System.Data.Common;


    namespace CrudApi.Controllers
    {
        [Route("api/[controller]")]
        [ApiController]
        public class HolidayController : ControllerBase
        {
            // Api Boiler Plate
            private readonly IConfiguration config;
            private readonly DbConnection _connection;
    
            public HolidayController(IConfiguration config, IDbConnectionFactory connectionFactory)
            {
                this.config = config;
                _connection = connectionFactory.CreateConnection();
            }
    
            // Gets all the Holiday in the DB
            [HttpGet]
            public async Task<ActionResult<List<Holiday>>> GetAllHoliday()
            {
                IEnumerable<Holiday> holiday = await SelectAllHoliday(_connection);
                return Ok(holiday);
            }
            private static async Task<IEnumerable<Holiday>> SelectAllHoliday(DbConnection connection)
            {
                return await connection.QueryAsync<Holiday>("select * from tbl03_holiday;");
            }
        }
    }  
    //test for controller
    using CrudApi.Controllers;
    using CrudApi.Models;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Data.Sqlite;
    using Microsoft.Extensions.Configuration;
    using Microsoft.VisualStudio.TestTools.UnitTesting;
    using System.Collections.Generic;
    using System.Data;
    using System.Threading.Tasks;
    using System.Data.Common;
    using System;


    namespace CrudApi.Tests
    {
        [TestClass]
        public class HolidayControllerTests
        {

            private static IConfiguration _config;
            private static DbConnection _connection; // Change the type to DbConnection
            private static HolidayController _controller;

            [ClassInitialize]
            public static void ClassInitialize(TestContext context)
            {
                var configBuilder = new ConfigurationBuilder();
                _config = configBuilder.Build();
    
                // Create an in-memory SQLite database connection factory
                var connectionFactory = new SqliteConnectionFactory("DataSource=:memory:;Cache=Shared");
                _connection = connectionFactory.CreateConnection();
                _connection.Open(); // Keep the connection open for the duration of the tests
    
                // Create the controller
                _controller = new HolidayController(_config, connectionFactory);
    
                // Initialize the database schema and populate with test data
                InitializeDatabase(_connection);
                
            }

            [ClassCleanup]
            public static void ClassCleanup()
            {
                // Cleanup resources
                if (_connection != null)
                {
                    _connection.Close();
                }
            }
    
            private static void InitializeDatabase(DbConnection connection)
            {
                if (connection.State == ConnectionState.Open)
                {
                    Console.WriteLine("connection is open");
                }
                else
                {
                    Console.WriteLine("connection is closed");
                }
                connection.Open(); // Open the connection

                using (var command = connection.CreateCommand())
                {
                    command.CommandText = @"
                        CREATE TABLE tbl03_holiday (
                            holiday_id INTEGER PRIMARY KEY AUTOINCREMENT,
                            uid TEXT NOT NULL,
                            from_date TEXT NOT NULL,
                            to_date TEXT NOT NULL,
                            holiday_type TEXT NOT NULL
                        );
    
                        INSERT INTO tbl03_holiday (holiday_id, uid, from_date, to_date, holiday_type) VALUES (1, 'test1', '0001-01-01', '00001-01-02', 'Holiday 1');
                        INSERT INTO tbl03_holiday (holiday_id, uid, from_date, to_date, holiday_type) VALUES (2, 'test2', '0001-01-01', '00001-01-02', 'Holiday 2');
                    ";
                    command.CommandType = CommandType.Text;
                    command.ExecuteNonQuery();
                    Console.WriteLine("Table created");
                }
            }
            private static void DisplayTableData(string tableName, DbConnection connection)
            {
                using (var command = connection.CreateCommand())
                {
                    command.CommandText = $"SELECT * FROM {tableName};";
                    using (var reader = command.ExecuteReader())
                    {
                        while (reader.Read())
                        {
                            for (int i = 0; i < reader.FieldCount; i++)
                            {
                                Console.Write($"{reader.GetName(i)}: {reader.GetValue(i)}\t");
                            }
                            Console.WriteLine();
                        }
                    }
                }
            }

            [TestMethod]
            public void TestDisplayTableData()
            {
                DisplayTableData("tbl03_holiday", _connection);
            }


            [TestMethod]
            public async Task GetAllHoliday_Returns_All_Holidays()
            {
                // Arrange
                if (_connection.State == ConnectionState.Open)
                {
                    Console.WriteLine("Connection is open");
                }
                else
                {
                    Console.WriteLine("Connection is closed");
                }

                //Print the connection string
                var connectionString = _connection.ConnectionString;
                Console.WriteLine($"Test method called with connection string: {connectionString}");

                // Act
                var result = await _controller.GetAllHoliday();

                // Assert
                Assert.IsNotNull(result);
                Assert.IsInstanceOfType(result.Result, typeof(OkObjectResult));
                var okResult = result.Result as OkObjectResult;
                Assert.IsInstanceOfType(okResult.Value, typeof(List<Holiday>));
                var holidays = okResult.Value as List<Holiday>;
                Assert.AreEqual(2, holidays.Count);
            }
        }
    }
My current output:
  Passed TestDisplayTableData [3 ms]
  Standard Output Messages:
 connection is open
 Table created
 holiday_id: 1  uid: test1      from_date: 0001-01-01   to_date: 00001-01-02    holiday_type: Holiday 1
 holiday_id: 2  uid: test2      from_date: 0001-01-01   to_date: 00001-01-02    holiday_type: Holiday 2


  Failed GetAllHoliday_Returns_All_Holidays [122 ms]
  Error Message:
   Test method CrudApi.Tests.HolidayControllerTests.GetAllHoliday_Returns_All_Holidays threw exception:
Microsoft.Data.Sqlite.SqliteException: SQLite Error 1: 'no such table: tbl03_holiday'.
  Stack Trace:
      at Microsoft.Data.Sqlite.SqliteException.ThrowExceptionForRC(Int32 rc, sqlite3 db)
   at Microsoft.Data.Sqlite.SqliteCommand.PrepareAndEnumerateStatements()+MoveNext()
   at Microsoft.Data.Sqlite.SqliteCommand.GetStatements()+MoveNext()
   at Microsoft.Data.Sqlite.SqliteDataReader.NextResult()
   at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReader(CommandBehavior behavior)
   at Microsoft.Data.Sqlite.SqliteCommand.ExecuteReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
   at Microsoft.Data.Sqlite.SqliteCommand.ExecuteDbDataReaderAsync(CommandBehavior behavior, CancellationToken cancellationToken)
   at Dapper.SqlMapper.QueryAsync[T](IDbConnection cnn, Type effectiveType, CommandDefinition command) in /_/Dapper/SqlMapper.Async.cs:line 434
   at CrudApi.Controllers.HolidayController.SelectAllHoliday(DbConnection connection) in 
  Standard Output Messages:
 Connection is open
 Test method called with connection string: DataSource=:memory:;Cache=Shared

如果我没有提供足够的信息,请随时说

c# postgresql sqlite mstest dapper
1个回答
0
投票

根据 Microsoft

使用特殊的数据源文件名:内存:创建内存中 数据库。当连接关闭时,数据库将被删除。 什么时候 使用:内存:,每个连接创建自己的数据库。

链接页面建议为持久内存数据库使用不同的连接字符串格式:

Data Source=InMemorySample;Mode=Memory;Cache=Shared
© www.soinside.com 2019 - 2024. All rights reserved.