如何跟踪Entity Framework Core事件以进行集成测试? [英] How to trace an Entity Framework Core event for integration testing?

查看:65
本文介绍了如何跟踪Entity Framework Core事件以进行集成测试?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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

  [事实] 
公共异步任务测试()
{
使用(var context = new FooContext())
{
//与上下文相关的代码来生成查询和命令
}

Assert.True(/ *与上下文相关的任何事务都已提交* /);
}

有可能吗?

解决方案

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



EF Core 1.1.2: RelationalEventId 枚举。



EF Core 2.0.0预览1:

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

  [事实] 
公共异步任务TransactionCommit_Logger_ContainsEvent()
{
var logger = new FakeLogger( );

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

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

Assert.True(logger.Events.Contains((int)RelationalEventId.CommittingTransaction));
}

FakeLogger 添加了一个将事件ID记录到 Events 列表中。

 公共类FakeLogger:ILogger 
{
public void Log< TState>(LogLevel logLevel,EventId eventId,TState状态,异常异常,
Func< TState,异常,字符串>格式化程序)
{
Events.Add(eventId.Id);
}

公共列表< int>活动{组; } = new List< int>();

public bool IsEnabled(LogLevel logLevel)=>真正;

public IDisposable BeginScope< TState>(TState状态)=>空值;
}

调用 UseLoggerFactory 到将工厂实例附加到上下文:

 公共类FooContext:FooParentContext 
{
private readonly ILoggerFactory _loggerFactory ;

public FooContext(){}

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

受保护的覆盖无效OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
base.OnConfiguring(optionsBuilder);

optionsBuilder.UseLoggerFactory(_loggerFactory);
}
}

P.S。您甚至可以更深入地分析日志消息,甚至可以分析EF产生的原始SQL


We need to ensure that EF Core-based code has performed a specific kind of database-level operation under test (for example, any command execution or any transaction commit).

Let's suppose a real database should be triggered and we can't isolate it by DbContext mocking. How could it look:

[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 */);
}

Is it possible?

解决方案

EF Core doesn't provide its own tracing mechanism. However, it logs a lot of database interaction events. We could gather these log messages and check their EventId to determine did a specific operation occur or not. Here is the list of relational events used by EF Core:

EF Core 1.1.2: RelationalEventId enum.

EF Core 2.0.0 preview 1: RelationalEventId class (breaking change!).

All we need to do is create a fake logger and pass it to context:

[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));
}

FakeLogger adds a logged event id to the Events list.

public class FakeLogger : ILogger
{
    public void Log<TState>(LogLevel logLevel, EventId eventId, TState state, Exception exception,
        Func<TState, Exception, string> formatter)
    {
        Events.Add(eventId.Id);
    }

    public List<int> Events { get; set; } = new List<int>();

    public bool IsEnabled(LogLevel logLevel) => true;

    public IDisposable BeginScope<TState>(TState state) => null;
}    

Call UseLoggerFactory to attach a factory instance to a context:

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);
    }
}

P.S. You could go even deeper and analyze log message or even raw SQL produced by EF.

这篇关于如何跟踪Entity Framework Core事件以进行集成测试?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆