C# 如何跟踪实体框架核心事件以进行集成测试?

C# 如何跟踪实体框架核心事件以进行集成测试?,c#,.net-core,entity-framework-core,C#,.net Core,Entity Framework Core,我们需要确保基于EF核心的代码在测试中执行了特定类型的数据库级操作(例如,任何命令执行或任何事务提交) 让我们假设一个真实的数据库应该被触发,我们不能通过DbContextmocking来隔离它。它看起来如何: [Fact] public async Task Test() { using (var context = new FooContext()) { //context-related code to produce queries and command

我们需要确保基于EF核心的代码在测试中执行了特定类型的数据库级操作(例如,任何命令执行或任何事务提交)

让我们假设一个真实的数据库应该被触发,我们不能通过
DbContext
mocking来隔离它。它看起来如何:

[Fact]
public async Task Test()
{
    using (var context = new FooContext())
    {
        //context-related code to produce queries and commands
    }

    Assert.True(/* any context-related transaction has been committed */);
}

可能吗?

EF Core不提供自己的跟踪机制。但是,它记录了许多数据库交互事件。我们可以收集这些日志消息并检查它们的
EventId
,以确定是否发生了特定操作。以下是EF Core使用的关系事件列表:

EF核心1.1.2:枚举

EF Core 2.0.0预览版1:类(突破性更改!)

我们需要做的就是创建一个假记录器并将其传递给上下文:

[Fact]
public async Task TransactionCommit_Logger_ContainsEvent()
{
    var logger = new FakeLogger();

    var factoryMock = new Mock<ILoggerFactory>();
    factoryMock.Setup(f => f.CreateLogger(It.IsAny<string>()))
        .Returns(logger);

    using (var context = new FooContext(factoryMock.Object))
    {
        using (var transaction = await context.Database.BeginTransactionAsync())
        {
            transaction.Commit();
        }
    }

    Assert.True(logger.Events.Contains((int)RelationalEventId.CommittingTransaction));
}
调用
UseLoggerFactory
将工厂实例附加到上下文:

public class FooContext : FooParentContext
{
    private readonly ILoggerFactory _loggerFactory;

    public FooContext() { }

    public FooContext(ILoggerFactory loggerFactory)
    {
        _loggerFactory = loggerFactory;
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        base.OnConfiguring(optionsBuilder);

        optionsBuilder.UseLoggerFactory(_loggerFactory);
    }
}

另外,您可以更深入地分析日志消息,甚至可以分析EF生成的日志消息。

假设您的事务是
cud
,您可以将数据读回并验证它是否正确
public class FooContext : FooParentContext
{
    private readonly ILoggerFactory _loggerFactory;

    public FooContext() { }

    public FooContext(ILoggerFactory loggerFactory)
    {
        _loggerFactory = loggerFactory;
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        base.OnConfiguring(optionsBuilder);

        optionsBuilder.UseLoggerFactory(_loggerFactory);
    }
}