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

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 when I created the first iteration of my application and it seems to me that test driven development might just be the ticket.
I was pleased to see that Visual Studio 2012 now natively supports TDD in C++, so I went ahead and read as much as I could. Unfortunately, Vs2012 is fairly new and I feel the documentation is somewhat lacking. But this is a little beside the point. I'm relying mainly on the following guide on the MSDN site:
http://msdn.microsoft.com/en-us/library/hh419385.aspx#objectRef
It fairly clearly states that if the code under testing is to be built as an .exe, then the way forward is creating a separate test project and linking the output object file. I'm guessing they mean the object files? Or maybe not?
I'm honestly a little confused as to how many .obj's I need to link. At first I thought I needed to link every single obj file which is fairly tedious.
If anyone has experience doing this and could perhaps also recommend which macros or similar short cuts to use in order to make this process as painless as possible, I'd be much obliged!

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.

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.
(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.)

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:

Related

MSVC 2019: Provide input files as text file to the linker

I use MSVC2019 for two C++ projects:
APP is a dynamic link library.
TEST is the automated test project.
TEST does not only perform tests on the API part of the DLL, but also on some non-published methods of APP ("unit tests"). Those methods are made visible to the TEST project by linking against the .obj files of the APP project.
Keeping this list of .obj files up-to-date becomes tedious lately. I wondered if there's a way to provide the list of files as input text file to the MSVC linker (see "Configuration Properties" -> "Linker" -> "Command line" -> "Additional options"). A script could generate the list of files easily and just pass it to the linker by piping from stdin.
My first attempt failed, simply adding "< myLinkerArguments.txt".
Example:
PATH_TO_LINKER\link.exe /ERRORREPORT:PROMPT /OUT:"G:\testproject\test_d.exe" < myLinkerArguments.txt
Any ideas if and how that's possible?
Thank you for reading,
Paul
According to the Microsoft documentation, you could try the following but different approaches:
The unit tests call non-member functions that aren't exported from the DLL, and the DLL can be built as a static library: Change the DLL project so that it's compiled to a .lib file. Add a separate test project that references the project under test.
This approach has the benefit of allowing your tests to use non-exported members, but still keep the tests in a separate project.
or
The unit tests must call non-member functions that aren't exported, and the code must be built as a dynamic link library (DLL): Add unit tests in the same project as the product code.
See https://learn.microsoft.com/en-us/visualstudio/test/how-to-write-unit-tests-for-cpp-dlls?view=vs-2022 for more information.
I would build a version of the DLL that is identical in every respect but which (also) exports the additional functions you want to test. Linking these in as separate object files sounds dangerous since then you have two copies - one in the .OBJ file and one in the DLL - and that might very well lead to trouble.
A practical way to achieve this is via a macro, let's call it EXPORT_FOR_TESTING, which can be #defined appropriately in the project file that builds the DLL.
So create yourself additional configuration(s) in there, one of which #defines EXPORT_FOR_TESTING as __declspec( dllexport ) and the other one can then define it as empty. After that, just link your test app with the test DLL and you're done.

How to link and built a project when your external SDK only has .dll, .lib, .h files

I have an external SDK that only contains a .dll, .lib, and .h files. I'm trying to use the SDK. Nothing in the dll is readable, but the .h files have some comments about the methods.
I'm not very c++ savvy. I assume I need to load the library, then read from the dll using the methods that are defined in the .h files. Correct?
I need to know how to write a cpp project where I can link all these files, read the dll, and be able to use the methods that are defined in the sdk.
Is there a test project with the project setup where I can see how this can be done?
Any help would be appreciated.
There's several ways to achieve this, including a shortcut method using #pragma that I'm not going to recommend in case it leads you to develop poor habits.
Similarly, you can use Property Sheets, but that may seem a bit overwhelming to start with. So I'm going to give you the standard middle-of-the-road approach...
In your project settings (Alt-F7 or Project > Properties...), you need to set these options:
C/C++ > General > Additional Include Directories
Add the folder you want to be searched when using the #include directive. Without complicating this with personal preference and style considerations, just set this to the directory where the SDK's header file lives.
You can use absolute or relative paths, environment variables. Whatever. I suggest for now you just use absolute path.
Linker > General > Additional Library Directories
Same as above, but this is where the .lib file resides.
Linker > Input > Additional Dependencies
This is the name of your lib file.
Now, if you #include the SDK's header file in your project's source and compile, it should hopefully work. And the linking step should also succeed.
If not, there may be extra things you need to make the SDK play nice (such as preprocessor definitions, compiler settings, or additional dependencies).
The last thing you need to worry about is that running your program might fail because the DLL cannot be found, unless it lives in a specific place that Windows searches. Rather than mess with DLL search paths etc, you can use a Post-Build Event to copy the DLL to the same directory where your executable was built.
Still, in the project properties:
Build Events > Post-Build Event
Add a command line something like:
copy "\Path\To\MySDK\MySDK.dll" "$(OutDir)\"
Now you should be all set to go, and not have to think about it again!

How can you Call a method from a diffrent Project, both in C++?

I'm normally working in c# so certain things in c++ keep confusing me alot (they seem so diffrent yet the names almost the same)
I created a Console project in which i want to run a diffrent project for testing purposes. i added the project as a reference to the console app, and then got kinda stuck.
there is no namespace in the projects, so i can't do a using and if i try to include the other file, it cannot find it (and i want to avoid being unable to debug through it all).
the code for the class can be found here(ignore the c# part), the console is just a standard console with nothing in it yet.
Yeah, C++ doesn't have the notion of assemblies that exists in C# and .NET. It makes tasks like this slightly more difficult, a virtue of the fact that C++ compiles directly to native code.
Instead, you'll generally #include the necessary header files (*.h) at the top of your code file, and instruct the linker to link to the appropriate .lib file(s). Do that by going to your project's Properties, selecting Linker -> Input, and adding the file to the "Additional Dependencies" section.
As an alternative to linking to the .lib file, you can use Visual Studio to add a reference to the other project, if it's part of the same solution. Microsoft has a walk-through on creating and using a dynamic link library in C++ that might be worth a read.
I'll assume you're using Visual Studios:-). You have to tell
the compiler where to look for its includes. Under Visual
Studios, open the properties page for the project, then go to
Configuration Properties->C/C++->General, and add the necessary
directories in the entry Additional Include Directories. (If
the other project is in the same solution, use a relative path.
But I think the dialog box that pops up when you click on the
button on the right does this automatically. I'm not a great
fan of all this GUI stuff in general, but Microsoft seems to
have done this particular part quite well.)
Once you've done this, you might have to go through a similar
process for linking: this time it's under Configuration
Properties->Linker->General, and the entry is called Additional
Library Directories, but the principle is the same. (This may
not be necessary, if you're putting all of the dll's and
executables in the project in the same directory.)

Precompiled headers question

I am right now reorganizing my project and what recently was a simple application now became a pair of C++ projects - static library and real application.
I would like to share one precompiled header between two projects, but face some troubles with setting up the .pdb file paths.
Assume my first project is called Library and builds it's .lib file with a corresponding Library.pdb file. Now, the second project is called Application and builds everything into the same folder (.exe and another Application.pdb file).
Right now my both projects create their own precompiled headers file (Library.pch and Application.pch) based on one actual header file. It works, but I think it's a waste of time and I also think there should be a way to share one precompiled header between two projects.
If in my Application project I try to set the Use Precompiled Header (/Yu) option and set it to Library.pch, it wouldn't work, because of the following error:
error C2858: command-line option 'program database name "Application.pdb" inconsistent with precompiled header, which used "Library.pdb".
So, does anyone know some trick or way to share one precompiled header between two projects preserving proper debug information?
The question is, why do you want to share the precompiled header (PCH) files. Generally I woul d say, that does not make sense. PCH are used to speed up compiling not to share any information between different projects.
Since you also write about the PDB file, you probably want to debug the library code with your applications. This can be achieved by setting the /Fd parameter when compiling the library. When you link the library in your application and the linker finds the corresponding PDB file, you get full debug support.
This sounds complicated and cumbersome to set up. More than that, it may not be possible at all.
Instead, you can include the precompiled header from one application into the second. It will still be compiled once for the second project, but maintenance becomes easy and you do not have to redefine the dependencies in the second project (just include them).

Visual C++ TDD setup

I haven't worked much with Visual Studio before. I've started a personal project in my spare time and I would like to use test-driven development since it has been a huge benefit to me in my Java development. I started this project quite a while ago, and I used CppUnit. I know there are probably other frameworks that are better, but this is what's already in place.
My Visual Stuido 2005 solution has 2 projects in it. It worked fine when the unit tests resided right alongside the application code. As the project grew in size, this became quite cumbersome and inelegant. I created a new project under my solution to house the unit tests (so it now has 3 projects). Everything went fine until I tried to build the solution. Everything compiled, but the unit test project failed to link. The output gives me 51 "unresolved external symbol" errors (LNK2019) for what seems like every function that my tests call.
As far as I can deduce, the problem is the directory structure that Visual Studio creates. Each project gets its own directory, and then below that are the object files and executables that get created. I think the problem is that, while the header files are properly included in each unit test, the linker can't find the cpp files because they are in a different directory. When it fails to find the implementation of a called function, it gives me the 2019 error.
Am I right in my evaluation of the problem? How can I fix it? Do I need to completely reorganize my projects or is it a simple configuration of the linker?
Thanks
Yes, your evaluation sounds pretty good. Try this: In the solution explorer, right click the name of the project that contains your tests and choose "Project Dependencies". Put a check by every project that it is dependent on. That should set up the linker settings so it automatically can find the correct files.
It sounds like the functions/classes that your test project is using from your main projects aren't exported. If code isn't exported, then nothing outside of the DLL/exe that the code lives in can reference it.
A common way that we handle this is to add a define to the project (in the project settings, go to Configuration Properties -> C/C++ -> Preprocessor, the first line has the defines) called something like PROJECTNAME_IMPL (make sure you do this for both Debug and Release configurations!). Then there is a header file (called ProjectNameExport.h) that anything exported includes, which contains something like the following:
#ifdef PROJECTNAME_IMPL
#define PROJECTNAME_API __declspec(dllexport)
#else
#define PROJECTNAME_API __declspec(dllimport)
#endif
Then, when defining a class (for example):
#include "ProjectNameExport.h"
class PROJECTNAME_API Foo
{
};
This has the result of exporting the class when the header file is included in a file within the project, and importing the class when the header file is included in a file in another project (that links to the first project, of course).
I always add the code to be tested to a separate static .lib file, and have the main application EXE and unit tests EXE depend on this. New code is added the .lib project, and the dependency support ensure the EXEs link with no errors. You need to make sure the EXE projects can find the .lib headers, but this will depend on your directory structure. You also have to watch that that the .lib and the EXEs are using the same CRT/MFC library (for example, when using the CRT you can statically link with it or use a DLL).
I find using libs in this way easier to maintain than adding files/headers to multiple projects.
I am using the Boost test framework but I would structure this the same no matter the TDD framework.
A good article on a similar setup can be found here:
http://www.codeproject.com/KB/architecture/Designing_Robust_Objects.aspx