2011-03-31 17 views
17

我们使用Visual Studio 2008开发C++应用程序并使用Boost.Test进行单元测试。目前,我们有一个单独的解决方案,其中包含我们的单元测试。单元测试DLL中的非导出类

我们在核心解决方案中的许多项目都生成DLL。我们的测试覆盖范围有限,因为我们无法测试非导出的类。

我对如何解决这些测试了两种思路:

  1. 出口一切
  2. 把DLL内部测试(同一项目和解决方案),并使用如Boost.Test对外亚军

我不完全确定这些缺点是什么。上面的数字1打破了模块级封装,数字2可能导致更大的DLL,除非可能只在特定配置中包含测试代码。

那么,上述方法是否存在严重缺陷,或者您能否想到其他解决方案?

+3

我想暗示[CMake](http://www.cmake.org)提供一个称为“对象库”的功能。 ('add_library(foo_obj OBJECT ...)')在我的项目中,我将源代码构建到对象库中,然后将它们链接到* DLL('add_library(foo SHARED ... $ )' )*和*它的测试驱动程序('add_executable(foo_test ... $ )')。这是使用不同构建系统的下面答案的变体(这就是为什么我将此添加为评论,而不是答案),但它解决了同样的问题。 – DevSolar 2015-08-25 12:47:01

回答

9

扩大汤姆Quarendon的回答this question,我已经使用了西蒙·斯蒂尔的反应轻微变种:

  • 创建一个测试项目(使用任何测试框架你喜欢,我用CppUnit)。
  • 在你的test_case.cpp,#include <header/in/source/project.h>
  • 在测试项目性质:
    • 在连接器 - >常规,添加源项目的$(IntDir)到附加库目录。
    • 在链接器 - >输入中,将.obj文件添加到其他依赖项。
  • 将测试项目的依赖项添加到Project-> Project Dependencies中的源项目中。

此外,唯一的维护开销是单元测试的标准测试开销 - 创建您要测试的单元的依赖性。

+2

有关此方法的另一个详细信息:如果您的测试中的DLL使用预编译头文件,链接以生成测试中的DLL的所有.obj文件取决于测试中的DLL的预编译头文件。在构建Test项目时,这会导致链接器错误LNK2011:未链接到的预编译对象;图像可能无法运行。除了要测试的特定对象文件之外,还必须添加stdafx.obj(如果您的PCH文件是通过编译stdafx.cpp生成的)。 – 2015-09-05 21:27:37

+0

关于此方法的另一个注意事项:如果您的测试项目使用多个包含需要测试的名称相同的对象文件的dll,则可以在链接器 - >输入设置中指定完整路径,例如$(SolutionDir)\ t \ $(Platform)\ $(Configuration)\ .obj'来区分它们。 – Edward 2016-05-12 09:28:07

+0

您可能还需要[/FORCE:MULTIPLE](https://msdn.microsoft.com/en-us/library/70abkas3.aspx),因为我刚发现。 – Rai 2016-09-30 12:23:42

3

我使用的解决方案是将相同的非导出代码构建到我的测试DLL中。这确实会增加构建时间,并且意味着将所有内容都添加到两个项目中,但可以节省导出所有内容或将测试放入主要产品代码中。

另一个可能性是将非导出的代码编译为DLL和导出的单元测试项目使用的lib。

+0

这可以适用于小型项目,但我们有很多代码,因此必须在两个地方进行更改将成为维护的噩梦。 – Jon 2011-03-31 08:24:08

+0

需要进行的唯一更改是添加或删除文件。因此,如果添加包含需要进行单元测试的代码的新CPP文件,则需要将其添加到两个项目中。没有两个源代码副本,每个包含可测试代码的源文件都包含在两个项目中。 – 2013-06-26 09:22:52

+0

这是我的第一个方法,它为我工作。我认为它有一个潜在的问题 - 有时一个dll项目使用不同于测试项目的编译标志。因此,dll和测试项目可以为同一个源文件创建不同的目标文件。虽然在我的情况下,我非常确定它们是相同的,但总的来说,测试dll项目创建的对象文件比测试项目创建的对象文件更安全。我最终将我的方法转换到了所描述的那个@Rai。 – 2017-10-05 18:24:48

0

尝试进行定义,如某处下面的所有文件将包括:

#define EXPORTTESTING __declspec(dllexport) 

而且用它来代替DLLEXPORT的,就像这样:

class EXPORTTESTING Foo 
{ 
... 
}; 

然后,你就可以关闭用于构建发行版DLL的标志,但将其保留为单元可测试的DLL。

+2

不确定这是一种很好的方法...可测试的代码不应该被修改来测试。即使它是一个简单的宏。 – toussa 2014-01-02 14:11:54

2

正在寻找一个解决方案,也许以下将更容易维护。

添加新的构建配置,例如“单元测试调试”到DLL项目,并将配置类型更改为“静态库.lib”(“常规” - >“配置类型”)。

然后,只需在您的单元测试中添加一个对此项目的依赖关系,现在当您使用新的构建配置“单元测试调试”时,所有内容都应该链接在一起。 如果您使用发布版本进行单元测试,那么您需要添加另一个配置并进行发布优化。

所以这个方案的好处是:

  • 低maintanability成本
  • 单个DLL /静态库项目
  • 不必手动链接到.obj文件

缺点:

  • 其他配置比曲线(S)将需要构建环境(CI)的一些变化
  • 大的编译时间

更新: 实际上,我们结束了使用不同的方法。

我们增加了新的“测试调试” /“测试版”的配置为我们每一个现有的项目。

有关的.exe/.dll项目,我们从编译停用原来的main.cpp并用它代替一个实例化测试框架(例如gtest)并运行所有测试,测试在单独的.cpp文件中,这些文件在常规配置(发布/调试)中也被排除在编译之外,并且仅在测试配置中启用并且仅在测试配置中启用。

.lib项目我们也有新的“Test debug”/“Test release”配置,我们将静态库转换为.exe文件,并提供一个main.cpp实例化测试框架a nd运行测试并测试自己。测试相关文件在发布/调试配置中排除在编译之外。