【问题标题】:How to mock StreamReader in NUnit如何在 NUnit 中模拟 StreamReader
【发布时间】:2021-11-16 22:44:20
【问题描述】:

我正在尝试使用 NUnit 和 Moq 为我的示例项目编写单元测试。我有如下服务类:

SentimentService.cs:

public class SentimentService : ISentimentService
{
    private readonly IStreamReader _reader;
    private readonly IServerClient _serverClient;

    public SentimentService(IStreamReader reader, IServerClient serverClient)
    {
        _reader = reader;
        _serverClient = serverClient;
    }


    public async Task<string> CalculateSentimentFromTextFile(IFormFile file)
    {
        var input = "";
        using (StreamReader streamReader = _reader.GetReader(file.OpenReadStream()))
        {
            input = streamReader.ReadToEnd();
            streamReader.Close();
        }

        var result = await _serverClient.PostAsync<SentimentResult, string>($"submit_string", input);

        return result.label;
    }
}

我尝试使用 Moq,如下所示:

[Test]
public async Task CalculateSentimentFromTextFileEquality()
{
    var mockFormFile = new Mock<IFormFile>();
    var mockStreamReader = new Mock<IStreamReader>();
    var mockServerClient = new Mock<IServerClient>();

    var mockResult = new SentimentResult
    {
        label = "Positive"
    };

    mockStreamReader.Setup(o => o.GetReader(mockFormFile.Object.OpenReadStream()));

    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"));
}

但是,得到以下错误:

【问题讨论】:

  • 能否告诉我们SentimentServiceTest 中的#35 是哪一行?

标签: c# unit-testing nunit asp.net-core-webapi moq


【解决方案1】:

这个设置:

 mockStreamReader.Setup(o => o.GetReader(mockFormFile.Object.OpenReadStream()));

不返回任何对象,因此在 SUT 中调用它时:

StreamReader streamReader = _reader.GetReader(file.OpenReadStream()

将返回一个空对象。

然而,StreamReader 有无参数构造函数,这意味着如果你想模拟它,你必须提供真实的文件路径/流。处理StreamReader 的一种方法是创建一个接口,该接口稍后可以由StreamReader 的包装器实现。

public interface IStreamReader : IDisposable
{
    string ReadToEnd();
    void Close();
}

IStreamReader 的创建是由工厂制造的:

public interface IStreamReaderFactory
{
    IStreamReader GetReader(Stream stream);
}

您的 SUT 可以修改为:

public class SentimentService : ISentimentService
{
    private readonly IStreamReaderFactory _readerFactory;
    private readonly IServerClient _serverClient;

    public SentimentService(IStreamReaderFactory readerFactory, IServerClient serverClient)
    {
        _readerFactory = readerFactory;
        _serverClient = serverClient;
    }


    public async Task<string> CalculateSentimentFromTextFile(IFormFile file)
    {
         var input = "";
         using (IStreamReader streamReader = _readerFactory.GetReader(file.OpenReadStream()))
         {
             input = streamReader.ReadToEnd();
             streamReader.Close();
         }

         var result = await _serverClient.PostAsync<SentimentResult, string>($"submit_string", input);

         return result.label;
    }
}

测试代码现在应该能够正确设置IStreamReader

var mockStreamReader = new Mock<IStreamReader>();
var mockStreamReaderFactory = new Mock<IStreamReaderFactory>();

mockStreamReaderFactory.Setup(o => o.GetReader(It.IsAny<Stream>())).Returns(mockStreamReader.Object);

【讨论】:

    猜你喜欢
    • 2020-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-12-31
    • 1970-01-01
    相关资源
    最近更新 更多