using Microsoft.Extensions.Logging;
using MongoDB.Bson.Serialization;
using MongoDB.Driver.Linq;

namespace Dpz.Core.ServiceTest;

[TestFixture]
public class UnitOfWorkTest : Basic
{
    private class UnitOfWorkTestEntity : BaseEntity
    {
        public string Value { get; set; } = "";
    }

    private class UnitOfWorkTestEntity2 : BaseEntity
    {
        public string Value { get; set; } = "";
    }

    [Test]
    public async Task TransactionTestAsync()
    {
        using var uow = GetService<IUnitOfWork>();
        var repository1 = uow.GetRepository<UnitOfWorkTestEntity>();
        var repository2 = uow.GetRepository<UnitOfWorkTestEntity2>();
        var logger = GetService<ILogger<UnitOfWorkTest>>();

        uow.Begin();
        await repository1.DeleteAsync(x => true);
        await repository2.DeleteAsync(x => true);

        var entity1 = new UnitOfWorkTestEntity { Value = Guid.NewGuid().ToString("N") };
        await repository1.InsertAsync(entity1);
        var entity2 = new UnitOfWorkTestEntity2 { Value = Guid.NewGuid().ToString("N") };
        await repository2.InsertAsync(entity2);

        logger.LogInformation("entity1 value:{Entity1}", entity1.Value);
        logger.LogInformation("entity2 value:{Entity2}", entity2.Value);

        await uow.CommitAsync();

        using var uow2 = GetService<IUnitOfWork>();
        var repository3 = uow2.GetRepository<UnitOfWorkTestEntity>();
        var repository4 = uow2.GetRepository<UnitOfWorkTestEntity2>();
        var guid1 = Guid.NewGuid().ToString("N");
        var guid2 = Guid.NewGuid().ToString("N");
        try
        {
            var list1 = await repository3.SearchFor(x => true).ToListAsync();
            Assert.That(list1, Is.Not.Null);
            Assert.That(list1, Is.Not.Empty);

            var list2 = await repository4.SearchFor(x => true).ToListAsync();
            Assert.That(list2, Is.Not.Null);
            Assert.That(list2, Is.Not.Empty);

            uow2.Begin();
            var entity3 = new UnitOfWorkTestEntity { Value = guid1 };
            var entity4 = new UnitOfWorkTestEntity2 { Value = guid2 };

            await repository3.InsertAsync(entity3);
            await repository4.InsertAsync(entity4);

            var r1 = await repository3.SearchFor(x => x.Value == guid1).FirstOrDefaultAsync();
            Assert.That(r1, Is.Not.Null);

            var r2 = await repository4.SearchFor(x => x.Value == guid2).FirstOrDefaultAsync();
            Assert.That(r2, Is.Not.Null);

            logger.LogInformation("fail entity3 value:{Entity3}", entity3.Value);
            logger.LogInformation("fail entity4 value:{Entity4}", entity4.Value);

            throw new Exception();
        }
        catch (Exception)
        {
            await uow2.RollbackAsync();
        }

        var repo1 = new Repository<UnitOfWorkTestEntity>(ConnectionString);
        var repo2 = new Repository<UnitOfWorkTestEntity2>(ConnectionString);

        var result1 = await repo1.SearchFor(x => x.Value == guid1).FirstOrDefaultAsync();
        Assert.That(result1, Is.Null);
        var result2 = await repo2.SearchFor(x => x.Value == guid2).FirstOrDefaultAsync();
        Assert.That(result2, Is.Null);
    }

    public void Test()
    {
        var serializerRegistry = BsonSerializer.SerializerRegistry;
        var documentSerializer = serializerRegistry.GetSerializer<SteamGame>();
        var update = Builders<SteamGame>.Update.Set(x => x.PlayTime, 100u);

        var updateArgs = new RenderArgs<SteamGame>(documentSerializer, serializerRegistry);

        Console.WriteLine(update.Render(updateArgs));
        update = update.Set(x => x.LastUpdateTime, DateTime.Now);

        Console.WriteLine(update.Render(updateArgs));
    }
}
⚠⚠    以下内容为AI分析的结果,请根据实际情况进行判断。

这是一个使用NUnit测试框架编写的单元测试类,主要用于测试工作单元(Unit of Work)模式的事务功能。让我逐部分解释这个代码:

类结构

[TestFixture]
public class UnitOfWorkTest : Basic
  • 这是一个测试类,继承自Basic基类
  • 使用[TestFixture]属性标记为NUnit测试固件

测试实体类

private class UnitOfWorkTestEntity : BaseEntity
{
    public string Value { get; set; } = "";
}

private class UnitOfWorkTestEntity2 : BaseEntity
{
    public string Value { get; set; } = "";
}
  • 定义了两个测试用的实体类,都继承自BaseEntity
  • 每个实体都有一个Value属性用于测试

主要测试方法:TransactionTestAsync()

这个方法测试了工作单元的事务功能,包括提交和回滚:

第一部分:成功的事务提交

using var uow = GetService<IUnitOfWork>();
var repository1 = uow.GetRepository<UnitOfWorkTestEntity>();
var repository2 = uow.GetRepository<UnitOfWorkTestEntity2>();

uow.Begin();
await repository1.DeleteAsync(x => true);  // 清空数据
await repository2.DeleteAsync(x => true);

// 插入新数据
var entity1 = new UnitOfWorkTestEntity { Value = Guid.NewGuid().ToString("N") };
await repository1.InsertAsync(entity1);
var entity2 = new UnitOfWorkTestEntity2 { Value = Guid.NewGuid().ToString("N") };
await repository2.InsertAsync(entity2);

await uow.CommitAsync();  // 提交事务

第二部分:事务回滚测试

using var uow2 = GetService<IUnitOfWork>();
// ... 获取仓储和生成测试数据

try
{
    // 验证之前提交的数据存在
    var list1 = await repository3.SearchFor(x => true).ToListAsync();
    Assert.That(list1, Is.Not.Null);
    Assert.That(list1, Is.Not.Empty);

    // 开始新事务并插入数据
    uow2.Begin();
    await repository3.InsertAsync(entity3);
    await repository4.InsertAsync(entity4);

    // 验证在事务中能查询到数据
    var r1 = await repository3.SearchFor(x => x.Value == guid1).FirstOrDefaultAsync();
    Assert.That(r1, Is.Not.Null);

    throw new Exception();  // 模拟异常
}
catch (Exception)
{
    await uow2.RollbackAsync();  // 回滚事务
}

第三部分:验证回滚效果

var repo1 = new Repository<UnitOfWorkTestEntity>(ConnectionString);
var repo2 = new Repository<UnitOfWorkTestEntity2>(ConnectionString);

// 验证回滚后数据不存在
var result1 = await repo1.SearchFor(x => x.Value == guid1).FirstOrDefaultAsync();
Assert.That(result1, Is.Null);
var result2 = await repo2.SearchFor(x => x.Value == guid2).FirstOrDefaultAsync();
Assert.That(result2, Is.Null);

Test()方法

这是一个简单的测试方法,演示了MongoDB的更新操作构建:

public void Test()
{
    var serializerRegistry = BsonSerializer.SerializerRegistry;
    var documentSerializer = serializerRegistry.GetSerializer<SteamGame>();
    var update = Builders<SteamGame>.Update.Set(x => x.PlayTime, 100u);

    var updateArgs = new RenderArgs<SteamGame>(documentSerializer, serializerRegistry);

    Console.WriteLine(update.Render(updateArgs));  // 输出更新语句
    update = update.Set(x => x.LastUpdateTime, DateTime.Now);
    Console.WriteLine(update.Render(updateArgs));  // 输出链式更新语句
}

总结

这个测试类的主要目的是:

  1. 测试事务提交:验证工作单元能够正确提交多个仓储的操作
  2. 测试事务回滚:验证当发生异常时,工作单元能够正确回滚所有操作
  3. 测试数据一致性:确保事务操作后数据状态的正确性
  4. 演示MongoDB更新操作:展示如何构建和渲染更新语句

这是一个典型的集成测试,用于验证工作单元模式在实际数据库操作中的正确性。

评论加载中...