Сначала создайте шаблонный код ведения журнала, чтобы разрешить вывод в ITestOutputHelper:
class TestLoggerProvider : ILoggerProvider
{
ITestOutputHelper _output;
public TestLoggerProvider(ITestOutputHelper output)
=> _output = output;
public ILogger CreateLogger(string categoryName)
=> new TestLogger(categoryName, _output);
public void Dispose()
{
}
}
class TestLogger : ILogger
{
string _categoryName;
ITestOutputHelper _output;
public TestLogger(string categoryName, ITestOutputHelper output)
{
_categoryName = categoryName;
_output = output;
}
public bool IsEnabled(LogLevel logLevel)
// NB: Only logging things related to commands, but you can easily expand
// this
=> _categoryName == DbLoggerCategory.Database.Command.Name;
public void Log<TState>(
LogLevel logLevel,
EventId eventId,
TState state,
Exception exception,
Func<TState, Exception, string> formatter)
{
// TODO: Customize the formatting even more if you want
//if (eventId == RelationalEventId.CommandExecuting)
//{
// var structure = (IReadOnlyList<KeyValuePair<string, object>>)state;
// var parameters = (string)structure.First(i => i.Key == "parameters")
// .Value;
// var commandText = (string)structure.First(i => i.Key == "commandText")
// .Value;
//}
_output.WriteLine(formatter(state, exception));
}
public IDisposable BeginScope<TState>(TState state)
=> null;
}
Затем убедитесь, что ваш DbContext может принимать внешние параметры.
class MyDbContext : DbContext
{
public MyDbContext(DbContextOptions<MyDbContext> options)
: base(options)
{
}
}
Наконец, подключите все вверх. Вот пример создания нового контекста для каждого теста. Используйте класс или приспособление коллекции , чтобы продлить время жизни контекста.
public class UnitTest1 : IDisposable
{
IServiceProvider _serviceProvider;
MyDbContext _db;
public UnitTest1(ITestOutputHelper output)
{
_serviceProvider = new ServiceCollection()
.AddLogging(x => x.AddProvider(new TestLoggerProvider(output)))
.AddEntityFrameworkSqlite()
.BuildServiceProvider();
_db = new MyDbContext(
new DbContextOptionsBuilder<MyDbContext>()
// Don't call UseLoggerFactory! (a new service provider would be
// created every time without ever getting disposed)
.UseInternalServiceProvider(_serviceProvider)
.UseSqlite("Data Source=:memory:")
.Options);
}
[Fact]
public void Test1()
{
_db.Database.ExecuteSqlRaw("-- Can you see me?");
}
public void Dispose()
{
_db.Dispose();
(_serviceProvider as IDisposable)?.Dispose();
}
}