Отказ от ответственности: я не буду предлагать прямое решение, как того требует OP, потому что я считаю, что этот вопрос является XY проблемой .Вместо этого я сосредоточусь на своем ответе на том, почему этот код так чертовски сложно протестировать, потому что да, более 30 строк «упорядочить» для тестирования 2 строк кода означают, что что-то пошло не так.
Краткий ответ
Этот метод не нуждается в тестировании, по крайней мере, на уровне единиц.
Длинный ответ
Проблема с текущей реализацией представляет собой комплекс проблем.
Первая строка: _dbContext.Settings.Where(s => s.SoftwareId == softwareId).ForEachAsync(s => s.IsDeleted = true);
содержит бизнес-логику (s.softwareId == softwareId, s.IsDeleted = true), а также логику EF (_dbContext, ForEachAsync).
Вторая строка: _dbContext.SaveChanges();
содержит только логику EF
Дело в том, что такие методы (которые смешивают проблемы) трудно проверить на уровне устройства.Отсюда тот факт, что вам нужны макеты и несколько десятков кода «Arrange», чтобы протестировать только 2 строки реализации!
На основании этой констатации у вас есть 2 варианта:
- Вы удаляете свой тестпотому что метод в основном содержит логику EF, которую бесполезно тестировать (подробнее см. эту большую серию статей )
- Вы извлекаете бизнес-логику и пишете реальный (и простой) модульный тест
Во втором случае я бы реализовал эту логику, чтобы можно было написать такой тест:
[Test]
public void ItShouldMarkCorrespondingSettingsAsDeleted()
{
var setting1 = new Setting(guid1);
var setting2 = new Setting(guid2);
var settings = new Settings(new[] { setting1, setting2 });
settings.DeleteAllSettingsLinkedToSoftware(guid1);
Assert.That(setting1.IsDeleted, Is.True);
Assert.That(setting1.IsDeleted, Is.False);
}
Легко писать, легко читать.
Как насчет реализации сейчас?
public interface ISettings
{
void DeleteAllSettingsLinkedToSoftware(Guid softwareId);
}
public sealed class Settings : ISettings
{
private readonly IEnumerable<Setting> _settings;
public Settings(IEnumerable<Setting> settings) => _settings = settings;
public override void DeleteAllSettingsLinkedToSoftware(Guid softwareGuid)
{
foreach(var setting in _settings.Where(s => s.SoftwareId == softwareId))
{
setting.IsDeleted = true;
}
}
}
public sealed class EFSettings : ISettings
{
private readonly ISettings _source;
private readonly DBContext _dbContext;
public EFSettings(DBContext dbContext)
{
_dbContext = dbContext;
_source = new Settings(_dbContext.Settings);
}
public override void DeleteAllSettingsLinkedToSoftware(Guid softwareGuid)
{
_source.DeleteAllSettingsLinkedToSoftware(softwareGuid);
_dbContext.SaveChanges();
}
}
При таком решении каждая проблема разделяется, что позволяет:
- Избавиться от насмешек
- Код бизнес-логики для действительно модульного тестирования
- Увеличение удобства обслуживания и читаемости