通过设计考虑简化测试,同时利用依赖注入 [英] Simplifying Testing through design considerations while utilizing dependency injection
问题描述
我们正在进行一个未开发的项目,需要对产品的逻辑和业务层进行返工.通过使用MEF(依赖项注入),我们实现了高水平的代码覆盖率,我相信我们有一个相当不错的产品.当我们研究一些更复杂的逻辑时,我发现单元测试越来越困难.
We are a few months into a green-field project to rework the Logic and Business layers of our product. By utilizing MEF (dependency injection) we have achieved high levels of code coverage and I believe that we have a pretty solid product. As we have been working through some of the more complex logic I have found it increasingly difficult to unit test.
我们正在使用CompositionContainer查询这些复杂算法所需的类型.由于必须进行冗长的模拟对象设置过程,因此我的单元测试有时很难进行,恰好适合于验证某些情况.我的单元测试通常要花比我要测试的代码更长的时间.
We are utilizing the CompositionContainer to query for types required by these complex algorithms. My unit tests are sometimes difficult to follow due to the lengthy mock object setup process that must take place, just right, to allow for certain circumstances to be verified. My unit tests often take me longer to write than the code that I'm trying to test.
我意识到这不仅是依赖注入的问题,而且还是整个设计的问题.方法设计不佳或缺乏组成应归咎于我过于复杂的测试?我尝试了基类测试,创建了常用的模拟对象,并确保尽可能多地利用容器来缓解此问题,但是我的测试始终最终变得非常复杂且难以调试.您看到了哪些技巧可以使这些测试简洁,可读和有效?
I realize this is not only an issue with dependency injection but with design as a whole. Is poor method design or lack of composition to blame for my overly complex tests? I've tried base classing tests, creating commonly used mock objects and ensuring that I utilize the container as much as possible to ease this issue but my tests always end up quite complex and hard to debug. What are some tips that you've seen to keep such tests concise, readable, and effective?
推荐答案
我的主观观点:
- MEF看起来像是一个非常不错的插件框架.它并非旨在成为成熟的DI框架.如果不需要实时可交换组件,请调查完整的DI/IoC容器框架 . Unity 是Microsoft的替代选择.
- 确保您不进行服务定位器反模式.尽可能使用接口的构造函数注入.参见Mark Seemann的这篇精彩的帖子和
- 获得一个非常好的模拟/隔离框架并学习使用它.我喜欢 Moq .尽可能尝试在被测系统上进行状态验证,而不是在模拟机上进行行为验证.
- 阅读单元测试的技巧.阅读有关单元测试的其他书籍和文章.练习 TDD .继续学习.
- 阅读清除代码,并确保您的类遵循 SOLID 原则(尤其是圈复杂度.
- 不用担心您的单元测试花费的时间比生产代码花费的时间还要长.不过,将测试像生产代码一样对待,并在保持可读性和可维护性的任何时候都删除重复项.
- MEF looks like a really nice plug-in framework; it's not designed to be a full-fledged DI framework. If you don't need the live swappable components, investigate full DI/IoC Container frameworks. Unity is Microsoft's alternative.
- Make sure you are not doing the Service Locator anti-pattern. Use constructor injection of interfaces whenever possible. See this great post by Mark Seemann and this one by Jimmy Bogard. Your statement that you "utilize the container as much as possible" is a concern - few classes need to know anything about the container.
- Get a really good mocking/isolation framework and learn to use it well. I love Moq. Try to do state verification on the system under test rather than behavior verification on the mock whenever possible.
- Read The Art of Unit Testing. Read other books and articles on unit testing. Practice TDD. Keep learning.
- Read Clean Code and insure that your classes follow the SOLID principles (especially the Single Responsibility Principle). Lengthy mock setup is a code smell; your classes are probably doing too much. High code coverage is nice, but a better metric might be cyclomatic complexity.
- Don't worry about your unit tests taking longer to write than the production code. Treat your tests like production code, though, and remove duplication whenever you can preserve readability and maintainability.
这篇关于通过设计考虑简化测试,同时利用依赖注入的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!