C ++单元测试传统代码:如何处理#include? [英] C++ Unit Testing Legacy Code: How to handle #include?

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

问题描述

我刚刚开始使用#include指令为具有大物理依赖性的旧代码模块编写单元测试。我一直在处理他们一些方法,觉得过度乏味(提供空标题打破长#include依赖列表,并使用#define防止类编译),并寻找一些更好的策略来处理这些问题。 / p>

我经常遇到一个问题,几乎每个头文件与一个空白版本重复,以分离整个我在测试的类,然后写



任何人都知道一些更好的做法吗?

解决方案

响应中的抑郁症是压倒性的...但不要害怕,我们有圣书去驱除传统C ++代码的恶魔



转到第127页:可怕的情况下包括依赖关系。(现在我甚至不在迈克尔·费舍斯的英里范围内,但在这里作为我可以管理的回答..)



问题:在C ++中,如果类A需要了解ClassB,则B类的声明被直接提升/文本包含在ClassA的源文件中。因为我们的程序员喜欢把它带到错误的极端,一个文件可以递归地包含一个zillion其他的。建立需要几年..但至少它建立..我们可以等待。



现在说在测试线下实例化ClassA很困难是一个低调。

  #includeTestHarness.h
#includeScheduler.h
TEST(create,Scheduler)//你的fave C ++测试框架宏
{
调度程序(fred);
}

这将会带来一连串的构建错误。 />
Blow#1 Patience-n-Persistence :每次加入一个,决定我们是否真的需要依赖。让我们假设SchedulerDisplay是其中之一,其displayEntry方法在Scheduler的ctor中调用。

Blow#2 Fake-it-till-you-make-it (感谢RonJ)

  #includeTestHarness.h
#includeScheduler.h
void SchedulerDisplay: :displayEntry(const string& entryDescription){}
TEST(create,Scheduler)
{
调度程序
}

pop是依赖和所有的transitive包括。
您还可以通过将Fake方法封装在Fakes.h文件中以重复使用来包含在测试文件中。

Blow#3 Practice :它可能不是总是那么简单..但你得到的想法。在第一次几场比赛后,打破deps的过程将变得容易机械



注意事项(我提到有警告吗? )




  • 我们需要为此文件中的测试用例单独构建;我们在程序中只能有1个SchedulerDisplay :: displayEntry方法的定义。因此,请为调度程序测试创建一个单独的程序。

  • 我们不打破程序中的任何依赖项,因此我们不会使代码更清洁。


  • 你的美学感可能会被冒犯一段时间。只是咬你的嘴唇,并与我们在一起明天



对于一个非常庞大的类,使用这种技术会导致严重的依赖问题。 随着时间的推移,这个测试程序可以放在谷仓后面,因为你提取了更多的类(有自己的测试)。 / p>

更多..请阅读这本书。无价。战斗!


I've just started writing unit tests for a legacy code module with large physical dependencies using the #include directive. I've been dealing with them a few ways that felt overly tedious (providing empty headers to break long #include dependency lists, and using #define to prevent classes from being compiled) and was looking for some better strategies for handling these problems.

I've been frequently running into the problem of duplicating almost every header file with a blank version in order to separate the class I'm testing in it's entirety, and then writing substantial stub/mock/fake code for objects that will need to be replaced since they're now undefined.

Anyone know some better practices?

解决方案

The depression in the responses is overwhelming... But don't fear, we've got the holy book to exorcise the demons of legacy C++ code. Seriously just buy the book if you are in line for more than a week of jousting with legacy C++ code.

Turn to page 127: The case of the horrible include dependencies. (Now I am not even within miles of Michael Feathers but here as-short-as-I-could-manage answer..)

Problem: In C++ if a classA needs to know about ClassB, Class B's declaration is straight-lifted / textually included in the ClassA's source file. And since we programmers love to take it to the wrong extreme, a file can recursively include a zillion others transitively. Builds take years.. but hey atleast it builds.. we can wait.

Now to say 'instantiating ClassA under a test harness is difficult' is an understatement. (Quoting MF's example - Scheduler is our poster problem child with deps galore.)

#include "TestHarness.h"
#include "Scheduler.h"
TEST(create, Scheduler) 	// your fave C++ test framework macro
{
  Scheduler scheduler("fred");
}

This will bring out the includes dragon with a flurry of build errors.
Blow#1 Patience-n-Persistence: Take on each include one at a time and decide if we really need that dependency. Let's assume SchedulerDisplay is one of them, whose displayEntry method is called in Scheduler's ctor.
Blow#2 Fake-it-till-you-make-it (Thanks RonJ):

#include "TestHarness.h"
#include "Scheduler.h"
void SchedulerDisplay::displayEntry(const string& entryDescription) {}
TEST(create, Scheduler)
{
  Scheduler scheduler("fred");
}

And pop goes the dependency and all its transitive includes. You can also reuse the Fake methods by encapsulating it in a Fakes.h file to be included in your test files.
Blow#3 Practice: It may not be always that simple.. but you get the idea. After the first few duels, the process of breaking deps will get easy-n-mechanical

Caveats (Did I mention there are caveats? :)

  • We need a separate build for test cases in this file ; we can have only 1 definition for the SchedulerDisplay::displayEntry method in a program. So create a separate program for scheduler tests.
  • We aren't breaking any dependencies in the program, so we are not making the code cleaner.
  • You need to maintain those fakes as long as we need the tests.
  • Your sense of aesthetics may be offended for a while.. just bite your lip and 'bear with us for a better tomorrow'

Use this technique for a very huge class with severe dependency issues. Don't use often or lightly.. Use this as a starting point for deeper refactorings. Over time this testing program can be taken behind the barn as you extract more classes (WITH their own tests).

For more.. please do read the book. Invaluable. Fight on bro!

这篇关于C ++单元测试传统代码:如何处理#include?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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