如何使用 dapper 和 nunit 为存储库服务中的更新功能编写集成测试?

How to write integration test for update function in repository services with dapper and nunit?

我正在开发一个 Blazor 服务器端项目。

当我尝试为我的存储库模式服务编写集成测试时,出现错误: System.PlatformNotSupportedException : This platform does not support distributed transactions.。 尝试使用第二个连接并查询所需数据是否真的保存会触发错误。

我的测试代码:


namespace CVUnitTests.IntegrationTests.Services
{
    public class SkilServiceTest
    {
        [TestFixture]
        public class YourFixture
        {
            private TransactionScope _scope;
            private ISkillService _skillService;
            private IConfigurationRoot _config;

                [SetUp]
            public void SetUp()
            {
               _config = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();
               _skillService = new SkillService(_config);
               _scope = new TransactionScope();
            }

            [TearDown]
            public void TearDown()
            {
                _scope.Dispose();
            }


            [Test]
            public async Task UpdateSkill_NewSkillIsSaved()
            {
                var skillToUpdate = new Skill()
                {
                    Name = "TestSkill",
                    Type = SkillType.Hardskill,
                    Category = "TestCategory"
                };
                await _skillService.UpdateSkill(skillToUpdate);
                using IDbConnection connection = new SqlConnection(DatabaseUtils.GetConnectionString(_config));
                var sql = "SELECT * FROM skill WHERE Name = TestSkill";
                var queriedSkill = connection.QuerySingle<Skill>(sql);
                Assert.AreEqual(queriedSkill, skillToUpdate);
            }
        }
    }
}

我发现 Query 可用于实现此目的,但我无法将我的两个查询包装成一个 using 因为该服务正在打开自己的连接:

public Task<bool> UpdateSkill(Skill skill)
        {
            if (GetSkill(skill.Id) != null)
            {
                using IDbConnection dbConnection = new SqlConnection(_connectionString);
                var parameters = new
                {
                    Id = skill.Id,
                    skill.Name,
                    Skilltype = skill.Type == SkillType.Hardskill ? "TRUE" : "FALSE"
                };
                var sql = "update skill SET Name = @Name, Skilltype = @Skilltype where id = @Id";
                dbConnection.Open();
                var result = dbConnection.ExecuteAsync(sql, parameters).Result;
                dbConnection.Close();
                return Task.FromResult(true);
            }
            else
            {
                using IDbConnection dbConnection = new SqlConnection(_connectionString);
                var parameters = new {skill.Name, Skilltype = skill.Type == SkillType.Hardskill ? 1 : 0};
                var sql = "insert into skill (Name, Skilltype) values (@Name, @Skilltype)";
                dbConnection.Open();
                var result = dbConnection.ExecuteAsync(sql, parameters).Result;
                dbConnection.Close();
                return Task.FromResult(false);
            }

我收到错误 This platform does not support distributed transactions. 即使我 运行 只是事务范围内的一个查询。

我也尝试从我的服务中读取 dbConnection 而不是创建一个新服务,但也没有成功。

我实际上可以在我的服务功能中使用多个,然后 return 技能,尽管它似乎有点将测试代码放入我的方法中。

有没有办法我仍然可以实现我想要的测试行为,或者我是否必须完全改变我的测试逻辑?

终于 运行 使用以下代码得到它:

{
    public class SkilServiceTest
    {
        [TestFixture]
        public class YourFixture
        {
            private TransactionScope _scope;
            private ISkillService _skillService;
            private IConfigurationRoot _config;
            private DatabaseUtils _databaseUtils;
                
            [SetUp]
            public void SetUp()
            {
               _config = new ConfigurationBuilder().AddJsonFile("appsettings.json").Build();
               _skillService = new SkillService(_config);
               
               _databaseUtils = new DatabaseUtils(_config);
               //wipe data and create empty table to execute tests on empty tables 
               _databaseUtils.DropTable("Skill");
               _databaseUtils.CreateSkillTable();
            }

            [TearDown]
            public void TearDown()
            {
                //wipe data so database manipulation within tests has no effect afterwards and does not interfere later tests
                _databaseUtils.DropTable("Skill");
            }

            
            

            [Test]
            public async Task UpdateSkill_NewSkillIsSaved()
            {
                Skill skillToUpdate = new Skill()
                {
                    Name = "TestSkill",
                    Type = SkillType.Softskill,
                    Category = "SomeCategory",
                    Id = 1
                };

                await _skillService.UpdateSkill(skillToUpdate);
                string sql_query = "SELECT * FROM skill WHERE name = \'TestSkill\'";
                Skill queriedSkill = null;
                using (IDbConnection connection = new SqlConnection(DatabaseUtils.GetConnectionString(_config)))
                {
                    connection.Open();
                    queriedSkill = connection.QuerySingle<Skill>(sql_query); 
                }
                
                Assert.IsTrue(queriedSkill.Equals(skillToUpdate));
            }
        }
    }

也必须更改 Update

 public async Task<bool> UpdateSkillAsync(Skill skill)
        {
                        
            var parameters = new {Id = skill.Id};
            var sql_query = "SELECT * FROM skill WHERE id = @Id";
            var queriedSkill = DbConnection_second.QuerySingleOrDefault<Skill>(sql_query, parameters);

            if (queriedSkill != null)
            {
                var sql = "update skill SET Name = @Name, Type = @Type, Category = @Category where id = @Id";
                var result = await DbConnection.ExecuteAsync(sql, skill);
                return true;
            }
            else
            {
                var sql = "insert into skill (Name, Type, Category) values (@Name, @Type, @Category)";
                var result = await DbConnection.ExecuteAsync(sql, skill);
                return false;
            } 
        }