C# 如何为使用流作为参数的方法编写unitTest

C# 如何为使用流作为参数的方法编写unitTest,c#,unit-testing,stream,C#,Unit Testing,Stream,我有类ImportProvider,我想为导入方法编写单元测试 但这应该是单元测试,所以我不想从一个文件读取到另一个流。 有什么想法吗 public class ImportProvider : IImportProvider { public bool Import(Stream stream) { //Do import return isImported; } } public interface IImportPro

我有类
ImportProvider
,我想为导入方法编写单元测试

但这应该是单元测试,所以我不想从一个文件读取到另一个流。 有什么想法吗

public class ImportProvider : IImportProvider
{ 
     public bool Import(Stream stream)
     {
         //Do import

         return isImported;
     }
}

public interface IImportProvider
{
      bool Import(Stream input);
}
这是单元测试:

[TestMethod]
public void ImportProvider_Test()
{
    // Arrange           
    var importRepository = new Mock<IImportRepository>(); 
    var imp = new ImportProvider(importRepository.Object);
    //Do setup...

    // Act
    var test_Stream = ?????????????
    // This working but not option:
    //test_Stream = File.Open("C:/ExcelFile.xls", FileMode.Open, FileAccess.Read);
    var result = imp.Import(test_Stream);

    // Assert    
    Assert.IsTrue(result);
}
[TestMethod]
public void ImportProvider_Test()
{
//安排
var importRepository=new Mock();
var imp=新的导入提供者(importpository.Object);
//做设置。。。
//表演
var测试\u流=?????????????
//这是一个可行但不可行的选择:
//test_Stream=File.Open(“C:/ExcelFile.xls”,FileMode.Open,FileAccess.Read);
var结果=导入(测试流);
//断言
断言(结果);
}

您可以使用MemoryStream为测试提供纯内存流。

使用MemoryStream。不确定函数需要什么,但要将UTF-8字符串填充到函数中,例如:

//Act
using (var test_Stream = new MemoryStream(Encoding.UTF8.GetBytes("whatever")))
{
    var result = imp.Import(test_Stream);

    // Assert    
    Assert.IsTrue(result);
}
编辑:如果您需要Excel文件,并且无法从磁盘读取文件,是否可以在测试项目中添加Excel文件作为嵌入式资源?看

然后,您可以像这样读取流:

//Act
using (var test_Stream = this.GetType().Assembly.GetManifestResourceStream("excelFileResource"))
{
    var result = imp.Import(test_Stream);

    // Assert    
    Assert.IsTrue(result);
}

使用像JustMock、TypeMock或MicrosoftFakes这样的隔离框架,您将能够模拟流


坏消息是,据我所知,它们都是付费的。

我的解决方案是将
包装在您自己的类中,让我们命名它为
StreamWrapper
,它实现了接口
IStream
。现在将导入签名更改为

public bool Import(IStream stream)

现在您可以模拟该流,如果您想在生产代码中使用它,您应该通过
StreamWrapper
否则模拟。

有什么原因不能像那样加载测试文件吗?@user2451446,因此,真正的问题是,您希望将Excel文件的内容输入到测试代码中,但不希望从Excel文件中读取该数据。您将不得不在某个地方做出妥协:要么将其作为集成测试,要么删除对流的特定内容的依赖resource@GazTheDestroyer,我喜欢当我声称自己是一个二分法的糟糕选择,而有人在混合中加入了第三个,完美的解决方案,选择。我从来没有想过资源。这完全解决了OP的需求。遗憾的是,我不能再+1了:)我不同意。如果文件嵌入到测试中,那么它仍然是测试而不是一个代码单元。您可以抽象出数据的实际来源,并测试数据是否可以正确处理。有多种方法可以嵌入数据。最明显的是生成一个实际的文件,然后将其作为“嵌入式资源”,或者针对某种类型的Excel DOM提供程序编写代码,动态生成预期格式的数据。您可以更改生产代码吗?如何使用任何有意义的数据模拟流?这不会有帮助,因为该方法显然需要流中的Excel数据(请参阅GazTheDestroyer答案的注释)@user2451446这取决于导入方法的内容、使用的内容、期望的内容等DavidArno我不明白你的意思是什么?如果您包装整个stream类,您将能够使用stream提供的所有功能,但与另一个类一起使用,我不知道它会在哪里失败。@Zbigniew,该模拟类必须在请求时提供Excel数据。无法从文件中读取数据。。。所以OP有一个不可能的情况。mock类不会解决
MemoryStream
也无法解决的任何问题。我认为它可以归结为两件事:1)有像NSubstitute这样完全免费使用的模拟框架,2)可以“模拟”流,而不必模拟实际的流类型,因为a)流类型本身可以在任意子类中直接扩展,b)如果您只需要能够读取或写入数据,那么内置的
内存流
类型可以在
语义和
字节[]
缓冲区之间提供接口。所以,这个答案并不能准确描述问题空间或潜在解决方案。@JonathanGilbert:你可能认为还有其他选择,你可能认为它们比这个更好,但我认为隔离框架是这个问题的潜在解决方案是没有争议的。好的,是的,从技术上讲,您可以使用模拟框架来创建模拟
对象。但是,您可以使用一个简单的子类更容易地创建模拟
对象。最重要的是,您在回答中声明,所有模拟框架都是付费的,这显然是不真实的。因此,你的回答是误导性的,即使前半部分在技术上是正确的,而且你的回答建议做一些“艰难的事情”,而没有表明或承认有更简单的方法。这就是为什么其他堆栈溢出成员将其评为较差答案的原因。这是不正确的,Microsoft赝品没有付费。应该删除该答案。@SkorunkaFrantišek:没有付费?它仅在Visual Studio ultimate或premium上可用。你知道每件多少钱吗?这是最贵的:D