Предыстория: я пишу тесты для сервисов, использующих ef core. Я хочу использовать sqllite, поскольку он реляционный.
Я написал базовый класс для тестов, которые будут использовать фиктивную фабрику баз данных, которую я написал для настройки основных общих вещей, таких как http mocking и DAL.
namespace Bll.UnitTests
{
public class TestBase : IDisposable
{
// pass httpclient as dependency, setup messageHandler for stubbing
protected HttpClient httpClient;
protected Mock<HttpMessageHandlerFake> fakeHttpMessageHandler = new Mock<HttpMessageHandlerFake> { CallBase = true };
protected Mock<Logger> loggerMock;
protected DalContext dataContext;
protected MockDbFactory mockDbFactory;
public TestBase()
{
mockDbFactory = new MockDbFactory();
httpClient = new HttpClient(fakeHttpMessageHandler.Object);
dataContext = mockDbFactory.testDb;
loggerMock = new Mock<Logger>(dataContext);
}
public void Dispose()
{
mockDbFactory.Dispose();
}
}
}
Вот моя фиктивная фабрика БД, которая должна просто установить соединение в памяти и, похоже, работает.
using Dal;
using Microsoft.EntityFrameworkCore;
using Moq;
using Microsoft.Data.Sqlite;
using System;
using System.Collections.Generic;
namespace Bll.UnitTests.Factories
{
// In-memory database only exists while the connection is open
public class MockDbFactory : IDisposable
{
private SqliteConnection connection;
public DalContext testDb;
public MockDbFactory()
{
OpenConnection();
testDb = GetTestDb();
}
public void Dispose()
{
CloseConnection();
}
private void OpenConnection()
{
connection = new SqliteConnection("DataSource=:memory:");
connection.Open();
}
private void CloseConnection()
{
connection.Close();
}
private DalContext GetTestDb()
{
var options = new DbContextOptionsBuilder<DalContext>()
.UseSqlite(connection)
.Options;
// Create the schema in the database
using (var context = new DalContext(options))
{
context.Database.EnsureCreated();
return context;
}
}
}
}
В моем тестовом классе datacontext удаляется, когда я отлаживаю тестируемую службу.
public class LocationServiceTest : TestBase
{
private LocationService sut;
public LocationServiceTest(): base()
{
sut = new LocationService(
httpClient,
loggerMock.Object,
dataContext
);
}
[Fact]
public async Task UpdateCountriesAsync_CallsCountryApiAndUpdatesDatabase()
{
// arrange
// setup get country data to return 2 countries
var temp = BuildCountryApiReturnable(2);
fakeHttpMessageHandler.Setup(f => f.Send(It.IsAny<HttpRequestMessage>())).Returns(new HttpResponseMessage
{
StatusCode = HttpStatusCode.OK,
Content = new StringContent(temp)
});
// act
try
{
var result = await sut.UpdateCountriesAsync();
// assert
Assert.True(dataContext.Country.Count() == 2);
Assert.True(dataContext.Location.Count() == 2);
}
catch(Exception e)
{
throw e;
}
}
Я думаю, что понимаю, что оператор использования необходим, так как это создаст мое соединение и избавится от него, но я пытаюсь сделать это вручную, чтобы я мог внедрить контекст данных в свою службу. Если мне придется обернуть все в оператор using, я буду вынужден изменить свой сервис.
using
в методеGetTestDb
и сделайте класс потребителя ответственным за удаление созданного контекста. Если да, тоCreateTestDb
было бы лучшим именем. - person Fabio   schedule 13.11.2018