При написании модульных тестов для одного из моих классов обслуживания в веб-API ASP.Net Core мне нужно было имитировать IFormFile. Поэтому я решил поиздеваться над этим (используя moq):
fileMock.Setup(x => x.CopyToAsync(It.IsAny<Stream>(), It.IsAny<CancellationToken>()))
.Callback(() =>
{
Console.WriteLine("File Copied");
})
.Returns(Task.CompletedTask);
Метод, который я хочу протестировать, с радостью принимает этот макет, и все выглядело нормально, пока я не проверил расположение файла, которое я указал для целей тестирования здесь:
.
Мне это показалось немного странным, поскольку я ожидал, что файл не будет создан (особенно потому, что мои операторы обратного вызова и возврата никогда не касаются потока). Я попытался изменить макет (например, без какого-либо обратного вызова или с немедленным закрытием потока), но не повезло, что файл все еще создается. Затем я проверил свою реализацию операции сохранения файла:
public async Task<Result> SaveFileToDiskAsync(string filePath, IFormFile file, CancellationToken token)
{
//Checking if values are correct
try
{
using (var stream = new FileStream(filePath, FileMode.Create))
{
await file.CopyToAsync(stream, token).ConfigureAwait(false);
return Result.Ok();
}
}
catch (Exception e)
{
//Logging
}
}
И вот здесь я застрял. Я не вижу, что не так с этим методом, особенно потому, что он, кажется, правильно работает с копированием файла (он просто делает это не в то время). Поэтому мой вопрос: есть ли лучший способ реализовать макет или метод остановки создания файла?
абстрагируйте доступ к файловому потоку. Это должно дать системе необходимую гибкость, чтобы не беспокоиться о реализации.





var stream = new FileStream(filePath, FileMode.Create)
буду создать файл.
Система тесно связана с фактической реализацией ввода-вывода. Это не абстракция, над которой можно посмеяться.
Абстрагируйте доступ к файловому потоку.
public interface IFileStreamProvider {
Stream Create(string path);
Stream Open(string path);
//...
}
Это должно дать системе необходимую гибкость, чтобы не беспокоиться о реализации.
private readonly IFileStreamProvider disk; //populated via constructor injection.
public async Task<Result> SaveFileToDiskAsync(string filePath, IFormFile file, CancellationToken token) {
//Checking if values are correct
try {
using (var stream = disk.Create(filePath)) {
await file.CopyToAsync(stream, token).ConfigureAwait(false);
return Result.Ok();
}
} catch (Exception e) {
//Logging
}
}
И протестировано изолированно
//...
var disk = new MemoryStream(); //
var diskMock = new Mock<IFileStreamProvider>();
diskMock
.Setup(_ => _.Create(It.IsAny<string>()))
.Returns(disk);
//...
Хотя фактическая реализация IFileStreamProvider.Create завершит создание FileStream.
Большое спасибо за этот замечательный пример и объяснение. Это многое прояснило.
var stream = new FileStream(filePath, FileMode.Create)буду создать файл. Вы тесно связаны с реальной проблемой реализации ввода-вывода. не абстракция, над которой можно посмеяться.