我问了一个相关的问题,但没有得到满意的答案。所以,也许我应该换个方式问。
大型 C 项目(例如 Perl 或 Ruby 甚至 Linux 内核)如何处理单元测试?或者甚至是任何函数式语言?
我熟悉依赖注入和抽象工厂 用于 OOP 中的测试,但我在非 OOP 中没有看到可扩展且可管理的等效项。例如,在 C 或 Haskell 中,会有一层又一层的函数,较高的函数隐式调用较低的函数。如何找到接缝来仅测试代码单元而不是其所有依赖项?
避免需要接缝的一种方法是保持调用依赖图的深度非常低。可以这么说,水平编码而不是垂直编码。将尽可能多的应用程序逻辑保留在“叶”函数中;并确保“节点”功能除了将数据连接到其他节点/叶功能之外不执行任何其他操作。然后,仅测试“叶子”功能;将“节点”功能留给集成测试。这种方法有效吗?
当今最大的软件仍然是用过程语言编写的。必须采用一些有效的方法。具有使用过程语言的大型软件并具有良好的单元测试经验的人可以发表评论吗?
I have asked a related question, but I did not get a satisfactory answer. So, perhaps I should ask it a different way.
How do large-scale C projects, like Perl or Ruby or even the Linux kernel, handle unit-testings? Or even in any functional language?
I am familiar with Dependency Injection and Abstract Factory for testings in OOP, but I don't see a scalable and manageable equivalence in non OOP. In C or Haskell, for example, there would be layers over layers of functions, higher ones implicitly calling the lower ones. How do I find seams to test just an unit of code instead of all its dependencies?
One way to avoid the need for seams all together is to keep the depths of call-dependency graph very low. Code horizontally rather than vertically, so to speak. Keep as much of the application logic as possible in the "leaf" functions; and make sure the "node" functions do no work other than plumbing the data to other node/leaf functions. Then, test only the "leaf" functions; leave the "node" functions out to integration tests. Is that approach effective?
The largest software today are still written in procedural languages. There must be some methodologies being employed that work. Could someone with experience with large-scale software in procedural languages with good unit-testings comment?
发布评论
评论(2)
函数式语言具有其他模块化结构(而不是对象),例如 ML 函子。 “依赖注入”基本上是“抽象事物”的美化名称,并且已经在函数式语言中使用了很长时间。
在所有范例中,测试都应遵循规范边界。如果您知道给定的一段代码(函数、方法、对象...)应该做什么,您应该根据此规范进行测试。对于叶函数,这将是单元测试,对于“节点”函数,如果您愿意,这可以被视为“集成测试”,但这实际上是相同的活动。
我认为您会发现相同的方法本质上适用于函数式编程,并且结果本质上相同;特别是,(重新)设计易于测试的代码也提高了其模块化和可维护性。
Functional languages have other constructs (than objects) for modularity, such as ML functors. "Dependency injection" is basically a glorified name for "abstracting over things" and has been used for ages in functional languages.
Testing, in all paradigms, should follow the specification boundaries. If you have an idea what a given piece of code (function, method, object...) is supposed to do, you should test against this specification. For leaf functions, this will be unit testing, for "node" function this can be considered "integration testing" if you like, but it's really the same activity.
I think you will find that the same methodologies essentially applies to functional programming, with essentially the same results; in particular, (re)designing code to be easy to test also improves its modularity and maintainability.
将代码设计得易于测试还可以提高其模块化性和可维护性。
事实并非如此。将代码设计得易于测试可以提高编写测试代码的简易性。
功能模块的自然划分通常对于单元测试来说并不是最方便的。这就是为什么如今如此多的 Java 代码被分解成微小的、分散的片段,而每个片段本身大多没有用处。
designing code to be easy to test also improves its modularity and maintainability.
Not true. Designing code to be easy to test improves the ease of writing test code.
Natural divisions of functional modules usually aren't the most convenient for unit testing. That's why so much Java code these days is broken into tiny, scattered pieces, with each piece mostly not useful by itself.