在控制器中,我有一个返回
FileStreamResult
对象的操作结果,在此之前该操作使用 byte[] ReadAllBytes(string path)
类的 File
。
行动结果:
public async Task<IActionResult> Download(string path)
{
var myfile = System.IO.File.ReadAllBytes(path);
MemoryStream stream = new MemoryStream(myfile);
return new FileStreamResult(stream, "application/pdf");
}
在我的 xUnit 测试项目中,我使用 Moq 进行设置。
模拟:
using IFileSystem = System.IO.Abstractions.IFileSystem;
private readonly Mock<IFileSystem> _fileSystem = new Mock<IFileSystem>();
测试方法:
[Fact]
public async Task Download_ShouldReturnPdfAsFileStreamResult_WhenIsFoundByPath()
{
//Arrange
var expected = new byte[]
{
68, 101, 109, 111, 32, 116, 101, 120, 116, 32, 99, 111, 110, 116,
101, 110, 255, 253, 0, 43, 0, 32, 0, 115, 0, 111, 0, 109, 0, 101,
0, 32, 0, 116, 0, 101, 0, 120, 0, 116
};
var path = _fixture.Create<string>();
_fileSystem.Setup(f => f.File.ReadAllBytes(It.IsAny<string>()))
.Returns(expected);
//Act
var result = await _sutController.Download(path )
.ConfigureAwait(false) as FileStreamResult;
//Assert
result.Should().NotBeNull();
//...
}
现在,当我运行测试时,我收到此异常:
留言:
System.IO.FileNotFoundException : Could not find file 'C:\Users\Admin\Desktop\GF\Tests\GF.Web.Controllers.Tests\bin\Debug\net6.0\Path69bdc5aa-695a-4779-b38e-12cb2df4c21a'.
Stack Trace:
SafeFileHandle.CreateFile(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options)
SafeFileHandle.Open(String fullPath, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize)
OSFileStreamStrategy.ctor(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize)
FileStreamHelpers.ChooseStrategyCore(String path, FileMode mode, FileAccess access, FileShare share, FileOptions options, Int64 preallocationSize)
FileStreamHelpers.ChooseStrategy(FileStream fileStream, String path, FileMode mode, FileAccess access, FileShare share, Int32 bufferSize, FileOptions options, Int64 preallocationSize)
File.ReadAllBytes(String path)
亚历山大在评论中建议的正确方法是这样的:
首先开始在Web和单元测试项目中安装nuget包https://www.nuget.org/packages/System.IO.Abstractions/:
Install-Package System.IO.Abstractions
接下来将IFileSystem注入到Controller
中public class DownloadsController : Controller
{
private readonly IFileSystem _fileSystem;
public DownloadsController(IFileSystem fileSystem)
{
_fileSystem = fileSystem;
}
///Code ....
}
当然还有在启动中配置依赖注入
现在在 Controller ActionResult 中使用
_fileSystem.File.ReadAllBytes(path)
而不是 System.IO.File.ReadAllBytes(path)
现在在测试类中只需在构造函数中注入 IFileSystem 模拟
using IFileSystem = System.IO.Abstractions.IFileSystem;
private readonly Mock<IFileSystem> _fileSystem = new Mock<IFileSystem>();
public DownloadsControllerTests()
{
_sutController = new DownloadsController(_fileSystem.Object);
}
并设置_fileSystem.File.ReadAllBytes:
_fileSystem.Setup(f => f.File.ReadAllBytes(It.IsAny<string>()))
.Returns(expected).Verifiable();
预计是
new byte[]
还有一种替代的纯模拟方法(Moq),无需添加任何 Nuget 包。 实现一个接口和类。然后依赖注入接口。 现在你可以在测试类中进行模拟了。
public interface IMyHelper
{
byte[] ReadByteArrayFromFile(string path);
}
public class MyHelper:IMyHelper
{
public byte[] ReadByteArrayFromFile(string path)
{
byte[] bytes = System.IO.File.ReadAllBytes(path);
return bytes;
}
}
[TestClass]
Mock<IMyHelper> myHelper = new Mock<IMyHelper>();
[TestInitialize]
public void SetUp()
{
myHelper.Setup(x => x.ReadByteArrayFromFile(It.IsAny<string>
())).Returns(new byte[123]);
}