我如何(或我)对具体依赖项进行单元测试
我有一个业务层类,它使用 System.IO.File 从各种文件中读取信息。为了对这个类进行单元测试,我选择用注入的依赖项替换对 File 类的依赖项,如下所示:
using System.IO;
public interface IFileWrapper
{
bool FileExists( string pathToFile );
Stream Open( string pathToFile );
}
现在我可以使用 Mock 测试我的类,一切正常。另外,我需要一个具体的实现。我有以下内容:
using System;
using System.IO;
public class FileWrapper : IFileWrapper
{
public bool FileExists( string pathToFile )
{
return File.Exists( pathToFile );
}
public Stream Open( string pathToFile )
{
return File.Open( pathToFile, FileMode.Open, FileAccess.Read, FileShare.Read );
}
}
现在我的业务类不再依赖于 System.IO.File 类,并且可以使用 IFileWrapper 的模拟进行测试。我认为没有必要测试 System.IO.File 类,因为我认为 Microsoft 已经对该类进行了彻底测试并在无数用途中得到了验证。
如何测试具体的 FileWrapper 类?虽然这是一个简单的类(低风险),但我有遵循相同方法的更大示例。如果不完成此操作,我就无法达到 100% 的代码覆盖率(假设这很重要)。
我想这里更大的问题是,如何弥合单元测试和集成测试之间的差距?是否有必要测试这个类,或者是否有一些属性来装饰这个类以将其从代码覆盖率计算中排除。
I have a business layer class that uses System.IO.File to read information from various files. In order to unit test this class I've chosen to replace the dependency on the File class with an injected dependency like so:
using System.IO;
public interface IFileWrapper
{
bool FileExists( string pathToFile );
Stream Open( string pathToFile );
}
Now I can test my class using a Mock and all is right with the world. Separately, I need a concrete implementation. I have the following:
using System;
using System.IO;
public class FileWrapper : IFileWrapper
{
public bool FileExists( string pathToFile )
{
return File.Exists( pathToFile );
}
public Stream Open( string pathToFile )
{
return File.Open( pathToFile, FileMode.Open, FileAccess.Read, FileShare.Read );
}
}
Now my business class is no longer dependent on the System.IO.File class and can be tested using a Mock of IFileWrapper. I see no need to test the System.IO.File class as I assume this has been thoroughly tested by Microsoft and proven in countless uses.
How do I test the concrete FileWrapper class? Though this is a simple class (low risk), I have larger examples that follow the same approach. I cannot approach 100% code coverage (assuming this is important) without completing this.
The larger question here I suppose is, how to bridge the gap between unit testing and integration testing? Is it necessary to test this class, or is there some attribute to decorate this class to exlcude this from code coverage calculation.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
根据经验,您应该对您编写的所有生产代码进行单元测试。但是,由于 .NET 设计方式的本质,总会有像 Adapter 这样的类上面的类无法进行正确的单元测试。
我个人的经验法则是,如果您可以将适配器中的每个成员减少到 圈复杂度 1 可以将其声明为 Humble Object。
AFAIK 没有办法从覆盖率报告中排除代码,但是您可以在单独的程序集中实现 Humble 对象,这些程序集可以免除覆盖率报告。
As a rule of thumb you should unit test all production code you write. However, due to the nature of how .NET is designed, there will always be classes like your Adapter class above that can't be properly unit tested.
My personal rule of thumb is that if you can reduce each member in the Adapter to a cyclomatic complexity of 1 it's okay to declare it a Humble Object.
AFAIK there are no ways to exclude code from coverage reports, but you can implement your Humble Objects in separate assemblies which are exempt from coverage reporting.
在您的情况下,测试 FileWrapper 是一项开销。除了作为包装器之外,它没有任何作用。所以我会选择将其排除在覆盖率计算之外的属性。
在其他情况下,您可以在 FileWrapper 等类型中拥有一些额外的逻辑,在这些情况下,集成测试可以帮助您。
一般来说,您应该分别使用这两种测试。集成测试应该处于更高的级别,测试两个组件之间的集成,因此如果您觉得需要测试这种依赖关系 - 继续,在其他情况下不要编写此类测试。集成测试总是比单元测试更复杂、运行时间更长、更难以维护,因此在编写每个集成测试之前应该三思而后行。这就是为什么我不会说如果您为 FileWrapper 编写一些测试,这将是一个集成测试。所以我的观点是,单元测试和集成测试之间没有差距,它们解决的是不同的问题。
In your case testing FileWrapper is an overhead. It has no any role except of being a wrapper. So I would go with attribute that is excluding it from coverage calculation.
In other cases you can have some additional logic in such kind of types like FileWrapper and in those cases Integration Testing could help you.
In general you should use this two kinds of testing separately. Integration testing should be on the higher level, testing integration between two components, so if you feel that you need to test this dependency - go on, in other case don't write such kind of tests. Integration tests always more complex, much longer to run and more hard to maintain than unit testing, so you should think twice before writing each integration test. Thats why I wouldn't say that if you will write some tests for FileWrapper this will be an Integration Test. So my point is that there is no gap between unit and integration testing, they are solving different problems.
适配器类的唯一目的是包装文件系统。因此,您可以进行一个单元测试来检查此行为是否正确。当包装器工作正常后,您可以放心地在其他地方使用测试替身。
你的单元测试应该非常简单,但必须使用具体的实现。这意味着它可能会相对较慢(> 5ms)并且对于安装/拆卸来说有些烦人。我对单元测试的定义是运行相对较快并测试少量代码(在本例中为一个类)。
然后,您必须非常小心,不要在类中放置任何额外的逻辑,否则该逻辑也将需要困难的单元测试。
第二种方法是通过集成测试或手动测试来解决这个问题。如果到处都使用这个类,您将很快发现任何错误。由于此类的复杂性很小,因此引入错误的风险很低。
The sole purpose of your adapter class is to wrap the filesystem. Therefore, you can make one unit test that checks this behaviour is correct. Having satisifed yourself the wrapper works correctly, you can then comfortably use a test double in it's place everywhere else.
Your unit test should be very simple, but must use the concrete implementation. This means it will probably be relatively slow (> 5ms) and somewhat annoying to setup/teardown. My definition of a unit test is one that runs relatively quickly and tests a small amount of code, in this case, one class.
You must then be very careful not to put any additional logic in the class, or that logic will too require a difficult unit test.
The second approach is to cover this in an integration test or manual testing. If this class is used everywhere, you will catch any errors there quickly. Since there is little complexity to this class, the risk of introducing errors is low.