Unit testing 如何对文件管理器类进行单元测试?

Unit testing 如何对文件管理器类进行单元测试?,unit-testing,tdd,nunit,Unit Testing,Tdd,Nunit,我编写了一个简单的类来管理业务对象 class Manager { string[] GetNames(); BObject GetObject(string name); void Saveobject(BObject obj); } 它将对象序列化/反序列化为本地磁盘上的文件。我为类编写单元测试并运行它们。到目前为止还不错。当我的测试在生成服务器上运行时,由于文件访问权限,我不允许在服务器上写入文件,因此出现了问题。很明显,我不能用那种方式测试 我想如何进行单元测试。我看到的一种方

我编写了一个简单的类来管理业务对象

class Manager
{ 
 string[] GetNames();
 BObject GetObject(string name);
 void Saveobject(BObject obj);
}
它将对象序列化/反序列化为本地磁盘上的文件。我为类编写单元测试并运行它们。到目前为止还不错。当我的测试在生成服务器上运行时,由于文件访问权限,我不允许在服务器上写入文件,因此出现了问题。很明显,我不能用那种方式测试


我想如何进行单元测试。我看到的一种方法是提取一个接口并创建一个模拟对象进行测试。但是我想测试这个类本身。我该怎么做呢?

该类可能会调用文件系统操作
file.OpenRead()
file.OpenWrite()
等(我假设这是C#由于驼峰式的大小写)。然后,您可以为这些操作创建一个接口,例如:

public interface IFileSystem {
    StreamReader OpenRead(string fileName);
    StreamWriter OpenWrite(string fileName);
}
并使
Manager
的构造函数以
IFileSystem
为例。然后,通过调用实际的
File.OpenRead()
File.OpenWrite()
方法,编写一个实现
IFileSystem
的(非模拟)类,并在生产代码中使用这个类。在测试中,您使用@Digger提到的模拟框架(我个人的偏好是,但我还没有尝试Rhino mock,所以我对此没有任何负面评论)来模拟
IFileSystem
,并使用模拟来验证调用的方法是否具有正确的序列化数据

编辑:每个请求,NUnit和Moq中的一个示例(我这里没有IDE,所以它未经测试;请随意更正):

[测试]
公共无效对象应序列化配置文件(){
var fileSystemMock=new Mock();
var stream=newmemoryStream();
Setup(f=>f.OpenWrite(“theFileNameYouExpect.txt”)。返回(newstreamwriter(stream)).Verifiable();
var manager=新的管理器(fileSystemMock.Object);
manager.SaveObject(新对象(…);
stream.Seek(0,SeekOrigin.Begin);
Assert.That(…);//在此处对流内容执行断言
fileSystemMock.Verify();//实际上不需要,但请验证是否调用了“OpenWrite”
}

在我看来,这取决于类中包含多少逻辑

如果管理器中有一些复杂的逻辑,那么按照Aasmund的建议抽象文件操作是有意义的,这样就可以独立于文件系统对逻辑进行测试。我这样做的时候,有些事情非常挑剔,足以保证额外的依赖关系

另一方面,如果除了调用序列化/反序列化代码之外没有什么逻辑,那么跳过单元测试并运行测试整个周期的集成测试通常是可以接受的(在内存中创建一个
boobject
,通过调用
SaveObject
将其持久化,使用
GetObject
将其读回,确保它与您首先持久化的对象相等)


如果您的构建环境无法运行集成测试,那么我会研究如何设置它,使其成为可能。

Ofc测试系统在实际条件下如何工作是有意义的,但这不是单元测试,而是集成测试或系统测试。这些必须准备一些特殊的环境。@driushkin是的。您是是的。但是我很好奇用单元测试来蒙混过关。)你的意思是在单元测试时验证StreamReader的内容?莫克(犀牛)能做到吗?你能提供一个简单的例子吗?
[Test]
public void BObjectShouldBeSerializedToFile() {
    var fileSystemMock = new Mock<IFileSystem>();
    var stream = new MemoryStream();
    fileSystemMock.Setup(f => f.OpenWrite("theFileNameYouExpect.txt")).Returns(new StreamWriter(stream)).Verifiable();
    var manager = new Manager(fileSystemMock.Object);

    manager.SaveObject(new BObject(...));

    stream.Seek(0, SeekOrigin.Begin);
    Assert.That(...); // Perform asserts on the stream contents here
    fileSystemMock.Verify(); // Not really necessary, but verify that `OpenWrite` was called
}