简体   繁体   English

我如何(或我)单元测试具体依赖

[英]How do I (or do I) unit test a concrete dependency

I have a business layer class that uses System.IO.File to read information from various files. 我有一个业务层类,它使用System.IO.File从各种文件中读取信息。 In order to unit test this class I've chosen to replace the dependency on the File class with an injected dependency like so: 为了对这个类进行单元测试,我选择用一个注入的依赖项来替换对File类的依赖,如下所示:

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. 现在我可以使用Mock来测试我的课程,所有这些都适合世界。 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. 现在我的业务类不再依赖于System.IO.File类,可以使用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. 我认为没有必要测试System.IO.File类,因为我认为这已经过Microsoft的全面测试,并在无数次使用中得到证明。

How do I test the concrete FileWrapper class? 如何测试具体的FileWrapper类? 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. 如果不完成此操作,我无法接近100%的代码覆盖率(假设这很重要)。

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. 是否有必要测试此类,或者是否有一些属性来装饰此类以从代码覆盖率计算中排除此类。

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. 但是,由于.NET的设计特性,总会有像上面的Adapter类这样的类无法正确进行单元测试。

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 . 我个人的经验法则是,如果你可以将适配器中的每个成员减少到1的圈复杂度 ,那么可以将它声明为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. AFAIK没有办法从覆盖率报告中排除代码,但您可以在单独的程序集中实现您的Humble对象,这些程序集免于覆盖率报告。

In your case testing FileWrapper is an overhead. 在您的情况下,测试FileWrapper是一种开销。 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. 在其他情况下,您可以在FileWrapper等类型中使用其他逻辑,在这些情况下,Integration Testing可以为您提供帮助。

The larger question here I suppose is, how to bridge the gap between unit testing and integration testing? 我想这里更大的问题是,如何弥合单元测试和集成测试之间的差距?

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 . 这就是为什么我不会说如果你要为FileWrapper编写一些测试,这将是一个集成测试 So my point is that there is no gap between unit and integration testing, they are solving different problems. 所以我的观点是单元测试和集成测试之间没有差距,他们正在解决不同的问题。

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. 这意味着它可能会相对较慢(> 5ms)并且设置/拆卸有点烦人。 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. 由于此类的复杂性很小,因此引入错误的风险很低。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM