Path of least resistance when unit testing C++ code in an exe, in Visual Studio 2012

前端 未结 3 879
挽巷
挽巷 2021-02-20 12:33

I\'m in need of some sage advice here. Long story short, I\'m rebuilding a - for me - relatively complex app comprised of about 7000 lines of code. I ran into a number of issues

相关标签:
3条回答
  • 2021-02-20 13:06

    This will depend on how you have your solution structured. The way I like to structure my solutions is to have three projects.

    • A .lib project that has my source code in it.
    • An executable project, linked with the .lib. This calls into the .lib in the main() call
    • A test project (exe), linked with the .lib.

    With this structure you can use the Add New Reference... button in the Common Properties section and the references will be sorted for you (except the header include path found in C++\General\Additional include directories).

    If you do not want to restructure your projects you can tell the linker about each obj file (Linker\Input\Additional dependencies). This may be a significant number of .obj files if you have a lot of classes that you want to test. Unfortunately, you may have issues if you use pre-compiled headers.

    I would suggest restructuring the projects if you can.

    0 讨论(0)
  • 2021-02-20 13:18

    Unit Test Project for a Native Application (.exe) Project

    • Add the Unit Test Project to the Solution
      Right Click on the Solution, Add, New Project. Under Visual C++, choose Native Unit Test Project.
    • Add the Application as a Reference to the Unit Test Project
      Right click the unit test project, Properties, Common Properties, References: Add the .DLL project as a reference. This tells MSVC to rebuild the application if it has changed since the last unit test build, before rebuilding the unit test project.
    • Tell MSVC to Where to Find the Application's Library and Object Files
      Right click the unit test project, Properties, Linker, General: Edit Additional Library Directories and add the path(s) to your applications object and library files.
    • Collect all the .obj and .lib Names
      Run this batch file from the subdirectory or subdirectories where your Application's object and library files are located, concatenate the .txt files if there is more than one directory. For convenience you might want to add the .txt file to your project.

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

    • Tell MSVC to Link the Application Object Files to the Unit Test Application
      Right click the unit test project, Properties, Linker, Input: Edit Additional Dependencies and add the application object filenames and library (.obj and .lib) file names (copy and past the files from ObjLibFileNames.txt).
      If your Application project uses precompiled headers, don't forget to include the precompiled header object file(s), usually stdafx.obj, If you omit it, you will get a LNK2011 error.

      Microsoft says "If you use precompiled headers, LINK requires that all of the object files created with precompiled headers must be linked in."

      I thought there would be a name collision if I added the object file containing my application's entry point, main(int argc, char *argv), but my unit test projects link successfully with or without main.obj. I have not tried linking a file with other entry point flavors (WinMain, wWinMain, wmain). If you have a name collision with one of those, you could aways change the name of your entry point (which would be weird): Properties, Linker, Advanced, edit the Entry point, and rename the Application's entry point function correspondingly. The option is not specified in the unit test project I just looked at, which I assume means default, which almost surely is main(int argc, char *argv).

      My main.cpp files have only one function (main) and no globals, i.e. no other part of the application refers to anything in main.cpp. I assume you can get away with omitting any object file if nothing in it is referenced by a linked file. Not worth the effort to figure out which satisfy that requirement for small applications. For large applications...good luck with that; Eventually you'll want to test all your execution paths anyway.

      You will likely have a precompiled header object file, stdafx.obj file in the unit test project as well as the one in your application project. That will not be a problem, as the default object file names for the precompiled header files are $(TargetName).pch, where $(TargetName) resolves the project name. I.e., the pch object files will have different names.

      Suggetion: Rather than copying the contents of my application's stdafx.h file into the corresponding unit test file, include the application's stdafx.h in the unit test project's stdafx.h file, so you don't have to update the unit test's version when the application's file changes. #include <stdafx.h> works, but I use the relative path between the two projects (if their relative paths are stable), or the full pathname of the application's source file if that's more stable, to be sure the right file is found. See difference-between-include-hpp-and-include-hpp for an unsettling explanation about how #include"header.h" and #include are interpreted. Spoiler: it's another implementation specific feature of C++.
      _________________________________________________________________________

      As an aside, precompiled header files are specified on a per source file (.cpp) basis. An individual .cpp file can use only one precompiled header file, but you can have more than one precompiled header file in the same project. See this:

    0 讨论(0)
  • 2021-02-20 13:19

    There's a nifty option when you use a project dependency, that lets you choose between linking the output file or having the IDE automatically select all the object files from the other project as dependencies.

    enter image description here

    (Don't worry about the .NET stuff in the screenshot, this was taken from an project where a C++/CLI DLL included a native static library project. Just do the same thing with a native test project including a native DLL or EXE project, choosing to link with the inputs.)

    0 讨论(0)
提交回复
热议问题