如何在NUnit中使用Moq模拟IStreamReader,解决单元测试运行报错问题
错误原因
IFormFile的OpenReadStream方法未配置Mock返回,默认返回null。同时你在设置IStreamReader.GetReader的Mock规则时,当场调用mockFormFile.Object.OpenReadStream()得到的流实例,和业务代码实际执行时调用file.OpenReadStream()生成的实例不是同一个对象,导致Mock规则匹配失败,GetReader不会返回预期值。IStreamReader.GetReader仅设置了调用匹配规则,未配置返回值,即使匹配到调用也会返回null,后续业务代码调用streamReader.ReadToEnd()时会触发空引用异常。
解决方案
修改测试代码,补全所有依赖的Mock规则即可,修改后的代码如下:
[Test] public async Task CalculateSentimentFromTextFileEquality() { // 构造测试用的文件流,写入测试文本 var testContent = "测试文本内容"; using var testStream = new MemoryStream(); using var writer = new StreamWriter(testStream); writer.Write(testContent); writer.Flush(); testStream.Position = 0; // Mock IFormFile,设置OpenReadStream返回我们构造的测试流 var mockFormFile = new Mock<IFormFile>(); mockFormFile.Setup(f => f.OpenReadStream()).Returns(testStream); var mockStreamReader = new Mock<IStreamReader>(); // 设置GetReader匹配任意流,返回实际的StreamReader实例读取测试流内容 mockStreamReader.Setup(o => o.GetReader(It.IsAny<Stream>())) .Returns(new StreamReader(testStream)); var mockServerClient = new Mock<IServerClient>(); var mockResult = new SentimentResult { label = "Positive" }; mockServerClient.Setup(o => o.PostAsync<SentimentResult, string>(It.IsAny<string>(), It.IsAny<string>())) .ReturnsAsync(mockResult); var sut = new SentimentService(mockStreamReader.Object, mockServerClient.Object); var result = await sut.CalculateSentimentFromTextFile(mockFormFile.Object); Assert.That(result, Is.EqualTo("Positive")); }
如果需要更严格的参数匹配,可以把It.IsAny<Stream>()替换为testStream,即可校验GetReader传入的流是否为IFormFile返回的测试流。
内容的提问来源于stack exchange,提问作者Setu Kumar Basak
相关产品推荐
相关产品推荐

