10

我在这里需要一些明智的建议。长话短说,我正在重建一个——对我来说——由大约 7000 行代码组成的相对复杂的应用程序。我在创建应用程序的第一次迭代时遇到了许多问题,在我看来,测试驱动开发可能只是问题所在。

我很高兴看到 Visual Studio 2012 现在原生支持 C++ 中的 TDD,所以我继续阅读尽可能多的内容。不幸的是,Vs2012 相当新,我觉得文档有些缺乏。但这有点离题了。我主要依赖 MSDN 网站上的以下指南:

http://msdn.microsoft.com/en-us/library/hh419385.aspx#objectRef

它相当清楚地指出,如果要将测试中的代码构建为 .exe,那么前进的方法是创建一个单独的测试项目并链接输出目标文件。我猜他们的意思是目标文件?或者可能不是?

老实说,我对需要链接多少个 .obj 感到有些困惑。起初我以为我需要链接每一个相当乏味的 obj 文件。

如果有人有这样做的经验并且也许还可以推荐使用哪些宏或类似的快捷方式以使此过程尽可能轻松,我将非常感激!

4

3 回答 3

6

这将取决于您如何构建解决方案。我喜欢构建我的解决方案的方式是拥有三个项目。

  • 一个 .lib 项目,其中包含我的源代码。
  • 一个可执行项目,与 .lib 链接。main()这会在调用中调用.lib
  • 与 .lib 链接的测试项目 (exe)。

使用此结构,您可以使用该部分Add New Reference...中的按钮,Common Properties并且将为您对参考进行排序(除了在 中找到的标题包含路径C++\General\Additional include directories)。

如果您不想重组您的项目,您可以告诉链接器每个 obj 文件 ( Linker\Input\Additional dependencies)。如果您有很多要测试的类,这可能是大量的 .obj 文件。不幸的是,如果您使用预编译的头文件,您可能会遇到问题。

如果可以的话,我建议重组项目。

于 2013-04-19T09:14:35.463 回答
3

当您使用项目依赖项时,有一个不错的选项,可让您在链接输出文件或让 IDE 自动选择来自其他项目的所有目标文件作为依赖项之间进行选择。

在此处输入图像描述

(不要担心屏幕截图中的 .NET 内容,这是取自 C++/CLI DLL 包含本机静态库项目的项目。只需对包含本机 DLL 或 EXE 项目的本机测试项目执行相同操作即可,选择与输入链接。)

于 2013-05-13T22:46:40.347 回答
2

本机应用程序 (.exe) 项目的单元测试项目

  • 将单元测试项目添加到解决方案
    右键单击解决方案,添加,新建项目。在Visual C++下,选择Native Unit Test Project
  • 添加应用程序作为对单元测试项目的引用
    右键单击​​单元测试项目、属性、通用属性、引用:添加 .DLL 项目作为引用。这告诉 MSVC 如果应用程序自上次单元测试构建后发生更改,则在重新构建单元测试项目之前重新构建应用程序。
  • 告诉 MSVC 在哪里可以找到应用程序的库和对象文件
    右键单击​​单元测试项目、属性、链接器、常规:编辑附加库目录并将路径添加到应用程序对象和库文件。
  • 收集所有 .obj 和 .lib 名称
    从应用程序的对象和库文件所在的一个或多个子目录运行此批处理文件,如果有多个目录,则连接 .txt 文件。为方便起见,您可能希望将 .txt 文件添加到您的项目中。

    : *** CollectObjLibFilenames.bat ***
    dir /B *.obj > ObjLibFilenames.txt
    dir /B *.lib >> ObjLibFilenames.txt

  • 告诉 MSVC 将应用程序对象文件链接到单元测试应用程序
    右键单击单元测试项目、属性、链接器、输入:编辑附加依赖项并添加应用程序对象文件名和库(.obj 和 .lib)文件名(复制和过去ObjLibFileNames.txt 中的文件)。
    如果您的应用程序项目使用预编译的头文件,请不要忘记包含预编译的头文件对象文件,通常是 stdafx.obj,如果省略它,您将收到LNK2011错误。

    微软说 “如果你使用预编译头文件,LINK 要求所有使用预编译头文件创建的目标文件都必须链接进去。”

    我认为如果我添加包含我的应用程序入口点的目标文件会发生名称冲突main(int argc, char *argv),但是我的单元测试项目在有或没有 main.obj 的情况下成功链接。我没有尝试将文件与其他入口点风格(WinMain、wWinMain、wmain)链接。如果您与其中之一发生名称冲突,您可以更改入口点的名称(这会很奇怪):属性、链接器、高级,编辑Entry point,并相应重命名Application的入口点函数。我刚刚查看的单元测试项目中没有指定该选项,我认为这意味着默认值,几乎可以肯定是main(int argc, char *argv).

    我的 main.cpp 文件只有一个函数(main)并且没有全局变量,即应用程序的其他部分没有引用 main.cpp 中的任何内容。如果链接文件没有引用任何对象文件,我假设您可以省略任何对象文件。不值得努力找出哪些满足小型应用程序的要求。对于大型应用程序......祝你好运;最终你还是要测试所有的执行路径。

    您可能会有一个预编译的头对象文件stdafx.obj单元测试项目中的文件以及应用程序项目中的文件。这不是问题,因为预编译头文件的默认目标文件名是 $(TargetName).pch,其中 $(TargetName) 解析项目名称。即,pch 目标文件将具有不同的名称。

    建议:与其将我的应用程序的stdafx.h文件的内容复制到相应的单元测试文件中,不如将应用程序的stdafx.h包含在单元测试项目的stdafx.h文件中,这样你就不必更新单元测试的版本了应用程序的文件更改。#include <stdafx.h>可以,但是我使用两个项目之间的相对路径(如果它们的相对路径稳定),或者如果更稳定,则使用应用程序源文件的完整路径名,以确保找到正确的文件。关于如何解释 #include"header.h" 和#include的令人不安的解释。剧透:这是 C++ 的另一个实现特定功能。
    ___________________________________________________________________顺便说

    一句,预编译的头文件是在每个源文件(.cpp) 的基础上指定的。一个单独的 .cpp 文件只能使用一个预编译头文件,但您可以在同一个项目中拥有多个预编译头文件。看到这个:

于 2016-03-18T03:08:07.433 回答