你如何引入单元测试投入大,传统的(C / C ++)codeBase的? [英] How do you introduce unit testing into a large, legacy (C/C++) codebase?

查看:201
本文介绍了你如何引入单元测试投入大,传统的(C / C ++)codeBase的?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们必须用C写的(用C ++的一个小,但越来越量)大的,多平台应用它已经发展了许多功能,你会期望在一个大型的C岁月/ C ++应用程序:

We have a large, multi-platform application written in C. (with a small but growing amount of C++) It has evolved over the years with many features you would expect in a large C/C++ application:


  • #IFDEF 地狱

  • 大文件,使人们难以隔离检验的code

  • 是太复杂,是功能容易测试

由于这code是针对嵌入式设备,这是一个很大的开销,以实际的目标运行。因此,我们希望做更多我们的开发和测试的快速循环,在本地系统上。但是,我们想避免的经典策略复制/粘贴到您的系统上的.c文件,修正错误,复制/粘贴回。如果开发商打算去的麻烦要做到这一点,我们希望以后能够重新创建相同的测试,并运行在一个自动化的方式。

Since this code is targeted for embedded devices, it's a lot of overhead to run it on the actual target. So we would like to do more of our development and testing in quick cycles, on a local system. But we would like to avoid the classic strategy of "copy/paste into a .c file on your system, fix bugs, copy/paste back". If developers are going to to go the trouble to do that, we'd like to be able to recreate the same tests later, and run in an automated fashion.

下面就是我们的问题:为了重构code更加模块化,我们需要它更容易测试。但为了引进自动化单元测试,我们需要更加模块化的。

Here's our problem: in order to refactor the code to be more modular, we need it to be more testable. But in order to introduce automated unit tests, we need it to be more modular.

一个问题是,由于我们的文件是如此之大,我们可能有一个调用在同一文件中的函数的 的,我们需要存根出做一个好的单元测试的文件中的函数。看起来这将是一个问题较少作为我们code的变得更加模块化,但这是一个很长的路要走。

One problem is that since our files are so large, we might have a function inside a file that calls a function in the same file that we need to stub out to make a good unit test. It seems like this would be less of a problem as our code gets more modular, but that is a long way off.

我们想过做标记为已知可检验的源头code。与评论一件事。然后,我们可以写测试的code脚本扫描源文件,在一个单独的文件编译它,并与单元测试联系起来。当我们修复缺陷,并添加更多的功能,我们可以慢慢引入的单元测试。

One thing we thought about doing was tagging "known to be testable" source code with comments. Then we could write a script scan source files for testable code, compile it in a separate file, and link it with the unit tests. We could slowly introduce the unit tests as we fix defects and add more functionality.

然而,令人担忧的是保持这种方案(包括所有必需的存根函数)将成为太麻烦,而且开发商会停止维护单元测试。所以另一种方法是使用一种工具,对于所有的code自动生成存根,并且该文件与该​​链接。 (我们已经发现,将做到这一点的唯一工具是一个昂贵的商业产品)但这种做法似乎的需要的,我们所有的code更加模块化之前,我们甚至可以开始,因为只有外部可来电存根。

However, there is concern that maintaining this scheme (along with all the required stub functions) will become too much of a hassle, and developers will stop maintaining the unit tests. So another approach is to use a tool that automatically generates stubs for all the code, and link the file with that. (the only tool we have found that will do this is an expensive commercial product) But this approach seems to require that all our code be more modular before we can even begin, since only the external calls can be stubbed out.

就个人而言,我宁愿有开发商认为他们的外部依赖,智能写自己的存根。但是,这可能是压倒性的存根出所有依赖的一个可怕的杂草丛生,万行的文件。这可能是很难说服他们需要维护他们所有的外部依赖存根开发商,但就是正确的方式做到这一点? (我听说另外一个说法是,一个子系统的维护者应保持其子系统的存根。但我不知道是否强迫开发人员编写自己的存根会导致更好的单元测试?)

Personally, I would rather have developers think about their external dependencies and intelligently write their own stubs. But this could be overwhelming to stub out all the dependencies for a horribly overgrown, 10,000 line file. It might be difficult to convince developers that they need to maintain stubs for all their external dependencies, but is that the right way to do it? (One other argument I've heard is that the maintainer of a subsystem should maintain the stubs for their subsystem. But I wonder if "forcing" developers to write their own stubs would lead to better unit testing?)

的#ifdefs ,当然,增​​加一个很大的方面的问题。

The #ifdefs, of course, add another whole dimension to the problem.

我们已经看了几个C / C ++基于单元测试框架,还有很多看起来精细的选择。但是,我们还没有发现任何东西,以缓解由code的毛球,没有单元测试到单元测试的code过渡。

We have looked at several C/C++ based unit test frameworks, and there are a lot of options that look fine. But we have not found anything to ease the transition from "hairball of code with no unit tests" to "unit-testable code".

因此​​,这里有我的问题,其他人谁已经通过这样的:

So here are my questions to anyone else who has been through this:


  • 什么是一个很好的起点?我们是否在正确的方向,还是我们失去了一些东西明显?

  • 什么工具也可能是帮助与过渡有用吗? (preferably自由/开源的,因为我们的预算,现在大致是零)

请注意,我们的编译环境是Linux / UNIX的基础,因此,我们不能使用任何Windows的唯一工具。

Note, our build environment is Linux/UNIX based, so we can't use any Windows-only tools.

推荐答案

我们没有发现任何东西,以缓解从过渡,没有单元测试,以单元测试的code'code的毛球。

"we have not found anything to ease the transition from "hairball of code with no unit tests" to 'unit-testable code'."

多么可悲 - 没有神奇的解决方案 - 只是很多艰苦的工作修正多年积累的技术债务

How sad -- no miraculous solution -- just a lot of hard work correcting years of accumulated technical debt.

有没有简单的过渡。你有一个大的,复杂的,严峻的问题。

There is no easy transition. You have a large, complex, serious problem.

您只能解决它在狭小的步骤。每一个微小的步骤包括以下内容。

You can only solve it in tiny steps. Each tiny step involves the following.


  1. 选择一个离散件code这是绝对必要的。 (不要在周围的垃圾蚕食边)挑选一个是重要的,一个组件 - 以某种方式 - 可以雕刻出休息。而单一的功能是理想的,它可能是功能的紊簇或者功能的整个文件。这没关系,开始为您的测试组件的东西不完美。

  1. Pick a discrete piece of code that's absolutely essential. (Don't nibble around the edges at junk.) Pick a component that's important and -- somehow -- can be carved out of the rest. While a single function is ideal, it might be a tangled cluster of functions or maybe a whole file of functions. It's okay to start with something less than perfect for your testable components.

弄清楚什么是应该做的。弄清它的界面应该是。要做到这一点,你可能需要做一些初步的重构,使你的目标实际上是一块独立。

Figure out what it's supposed to do. Figure out what it's interface is supposed to be. To do this, you may have to do some initial refactoring to make your target piece actually discrete.

写一个整体融合测试 - 现在 - 测试你的离散件code的更多或更少,因为它被发现。得到这个你尝试改变任何东西显著前通过。

Write an "overall" integration test that -- for now -- tests your discrete piece of code more-or-less as it was found. Get this to pass before you try and change anything significant.

重新构建code到整洁,测试的单元,使比你目前的毛球感更好。你将不得不保持一定的向后兼容性(现在)与整体集成测试。

Refactor the code into tidy, testable units that make better sense than your current hairball. You're going to have to maintain some backward compatibility (for now) with your overall integration test.

编写单元测试的新单位。

Write unit tests for the new units.

一旦所有的传球,淘汰旧的API和解决什么将被改变被打破。如果有必要,返工原有集成测试;它测试旧的API,你要测试新的API。

Once it all passes, decommission the old API and fix what will be broken by the change. If necessary, rework the original integration test; it tests the old API, you want to test the new API.

迭代。

这篇关于你如何引入单元测试投入大,传统的(C / C ++)codeBase的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆