I want to create unit tests for a Visual C++ project. I tried following these MSDN instructions. I've found pages where they differentiate between unmanaged/mixed/pure code, but I don't fully understand those concepts. My code doesn't use .NET and would likely compile under MinGW with a few code adjustments.
My main project builds an executable, so I followed the steps under To reference exported functions from the test project. For starters I got different project options:
I went with Native Unit Test Project. I added a reference to my main project and I set Include Directories to $(SolutionDir)\Cubes;$(IncludePath). I wrote my code and got this when compiling:
1>Creating library C:\Users\Pieter\Dropbox\Unief\TTUI\TTUIproject\Cubes\Debug\CubesTest.lib and object C:\Users\Pieter\Dropbox\Unief\TTUI\TTUIproject\Cubes\Debug\CubesTest.exp
1>LayoutTest.obj : error LNK2019: unresolved external symbol "public: __thiscall Room::Room(void)" (??0Room##QAE#XZ) referenced in function "public: void __thiscall CubesTest::LayoutTest::NumOfRoomsConsistency(void)" (?NumOfRoomsConsistency#LayoutTest#CubesTest##QAEXXZ)
1>LayoutTest.obj : error LNK2019: unresolved external symbol "public: __thiscall Layout::Layout(class Room *,int)" (??0Layout##QAE#PAVRoom##H#Z) referenced in function "public: void __thiscall CubesTest::LayoutTest::NumOfRoomsConsistency(void)" (?NumOfRoomsConsistency#LayoutTest#CubesTest##QAEXXZ)
1>LayoutTest.obj : error LNK2019: unresolved external symbol "public: void __thiscall Layout::add(int,int,class Room *)" (?add#Layout##QAEXHHPAVRoom###Z) referenced in function "public: void __thiscall CubesTest::LayoutTest::NumOfRoomsConsistency(void)" (?NumOfRoomsConsistency#LayoutTest#CubesTest##QAEXXZ)
1>LayoutTest.obj : error LNK2019: unresolved external symbol "public: void __thiscall Layout::clear(int,int,bool)" (?clear#Layout##QAEXHH_N#Z) referenced in function __catch$?NumOfRoomsConsistency#LayoutTest#CubesTest##QAEXXZ$0
1>C:\Users\Pieter\Dropbox\Unief\TTUI\TTUIproject\Cubes\Debug\CubesTest.dll : fatal error LNK1120: 4 unresolved externals
If I'm not mistaken, this means that the compiler finds the header files, but not the source files. What am I missing?
Here is a step-by-step description on how to add an EXE as an unit-test target.
The key point is to "export" the functions/classes you want to test... You can download the complete sample here: http://blog.kalmbachnet.de/files/CPP_UnitTestApp.zip (I did not change any project settings, so all changes you can see in the source-code; of course, some parts can be made in the project settings).
Create a Win32 Application (Console or MFC or Windows, does not matter); I created a console project called CPP_UnitTestApp:
Add a function you want to test (you can also add classes). For example:
int Plus1(int i)
{
return i+1;
}
Add a header file for the functions you want to test: CPP_UnitTestApp.h
Put the declaration of the methods into the header file, and also export these functions!
#pragma once
#ifdef EXPORT_TEST_FUNCTIONS
#define MY_CPP_UNITTESTAPP_EXPORT __declspec(dllexport)
#else
#define MY_CPP_UNITTESTAPP_EXPORT
#endif
MY_CPP_UNITTESTAPP_EXPORT int Plus1(int i);
Include this header file in the main-cpp (here CPP_UnitTestApp.cpp) and define the EXPORT_TEST_FUNCTIONS before including the header:
#define EXPORT_TEST_FUNCTIONS
#include "CPP_UnitTestApp.h"
Now add a new project (Native unit test project: UnitTest1)
Include the header and the lib to the "unittest1.cpp" file (adopt the paths as you want):
#include "..\CPP_UnitTestApp.h"
#pragma comment(lib, "../Debug/CPP_UnitTestApp.lib")
Go to the project settings of the test project add add a reference to the "UnitTest1" project (Project|Properties|Common Properties|Add New Reference...: Select under "Projects" the "CPP_UnitTestApp"-Project)
Create the unit test function:
TEST_METHOD(TestMethod1)
{
int res = Plus1(12);
Assert::AreEqual(13, res);
}
Run your unit test ;)
As you can see, the main point was to export the function declaration! This is done via __declspec(dllexport) even if it is an EXE.
As I said, the demo project can be downloaded here: http://blog.kalmbachnet.de/files/CPP_UnitTestApp.zip
Related
Using Visual Studio 2017, I am trying to build my latest project which imports libraries, which in turn import methods and functions from .dll files.
When building my project, I get a list of errors like this:
error LNK2001: unresolved external symbol "__declspec(dllimport) void __cdecl UserTracking(void *)" (__imp_?UserTracking##YAXPEAX#Z)
error LNK2001: unresolved external symbol "public: bool __cdecl EACServer::Destroy(void)const " (?Destroy#EACServer##QEBA_NXZ)
error LNK2001: unresolved external symbol "public: bool __cdecl EACServer::Initialize(void)const " (?Initialize#EACServer##QEBA_NXZ)
...
All of the functions listed are from imported libraries.
As an example, the EACServer::Initialize method is defined as so in EACServer.h:
bool Initialize() const;
In the code I am compiling, this function is used as so (the appropriate header files are imported in the .h file ofc):
this->eacServer = EACServer();
this->eacServer.Initialize();
The class definition of EACServer is basic:
class EACServer : IRoot {
...
}
I have been told that these errors are thrown because I am missing the macro which correctly sets the __declspec.
How can I find/implement this macro?
Turns out that although I added the paths to my libraries in the linker additional library directories, I had neglected to add the .lib files in the linker additional dependencies.
I've got a VC++ project, and I'm attempting to use the extension of the gumbo-query library, found here. This library wraps/extends Google's gumbo-parser found here. The following is the exact steps I've taken - I'm not very familiar with importing libraries, so I've done what I do to use the Boost libraries:
In Visual Studio (VS Community 2013), under the project settings -> Configuration Properties -> C/C++ -> General I have put the path to a folder that contains all of the source files from both of the projects linked above. Specifically, I placed the .c, .cpp and .h files from the src folder of both projects and referenced these in my projects settings as an include directory.
Following the example file for the project that extends Google's gumbo-parser (found here), I added these two lines to import the library:
#include "Document.h"
#include "Node.h"
At this point, my solution compiles fine. However, continuing to follow the example file, adding the first variable declaration:
CDocument d;
Causes a linker error, as follows:
1>Main.obj : error LNK2028: unresolved token (0A0003B7) "public: __thiscall CDocument::CDocument(void)" (??0CDocument##$$FQAE#XZ) referenced in function "private: void __clrcall MyApplication::Main::worker_DoWork(class System::Object ^,class System::ComponentModel::DoWorkEventArgs ^)" (?worker_DoWork#Main#MyApplication##$$FA$AAMXP$AAVObject#System##P$AAVDoWorkEventArgs#ComponentModel#4##Z)
1>Main.obj : error LNK2028: unresolved token (0A0003B8) "public: virtual __thiscall CDocument::~CDocument(void)" (??1CDocument##$$FUAE#XZ) referenced in function "private: void __clrcall MyApplication::Main::worker_DoWork(class System::Object ^,class System::ComponentModel::DoWorkEventArgs ^)" (?worker_DoWork#Main#MyApplication##$$FA$AAMXP$AAVObject#System##P$AAVDoWorkEventArgs#ComponentModel#4##Z)
1>Main.obj : error LNK2019: unresolved external symbol "public: __thiscall CDocument::CDocument(void)" (??0CDocument##$$FQAE#XZ) referenced in function "private: void __clrcall MyApplication::Main::worker_DoWork(class System::Object ^,class System::ComponentModel::DoWorkEventArgs ^)" (?worker_DoWork#Main#MyApplication##$$FA$AAMXP$AAVObject#System##P$AAVDoWorkEventArgs#ComponentModel#4##Z)
1>Main.obj : error LNK2019: unresolved external symbol "public: virtual __thiscall CDocument::~CDocument(void)" (??1CDocument##$$FUAE#XZ) referenced in function "private: void __clrcall MyApplication::Main::worker_DoWork(class System::Object ^,class System::ComponentModel::DoWorkEventArgs ^)" (?worker_DoWork#Main#MyApplication##$$FA$AAMXP$AAVObject#System##P$AAVDoWorkEventArgs#ComponentModel#4##Z)
1>..{omitted}..\MyApplication.exe : fatal error LNK1120: 4 unresolved externals
This error appears to occur no matter where I put a CDocument instantiation.
What can I do to rectify this? VS seems to think the includes are fine, and moreso when I put in CDocument d; it lights up to show it recognises the CDocument type.
As always, it's clear I've been a JS developer for too long. I really did need to compile a .lib file. Thank you to Christian for reminding me of this.
The original gumbo-parser project by Google includes a VS project. I opened this and compiled it, fixing all of the project settings problems so that I could import it into my project, which I did via the Configuration Properties -> Linker -> Input -> Additional Dependencies setting for my VS project.
Next, I added the extra source files from the wrapper library gumbo-query, where I had to fix a naming conflict between parser.h/parser.cpp from the original gumbo-parser project and the Parser.h/Parser.cpp file in the wrapper library. I also changed all references to #include <gumbo.h> to #include "gumbo.h"
Eventually, I got a gumbo.lib file containing both the original and the wrapper libraries, and this imported into my project and I now seem to be able to successfully use the functions.
I'm trying to use the glog logging library (LINK).
In VS2012 (I'm on Windows 8 Professional 64-bit (Japanese)), I create an empty solution with a single main.cpp file like the one in the documentation (LINK).
Also I import the glog project inside the solution (either the dll one or the static library one) and set the project dependency.
To avoid some errors I have to comment out line 97 from port.h:
/* In windows-land, hash<> is called hash_compare<> (from xhash.h) */
#define hash hash_compare
While glog compiles, the main application gives me unresolved external symbol erros (with both dll and static version).
1>main.obj : error LNK2019: 未解決の外部シンボル "void __cdecl google::InitGoogleLogging(char const *)" (?InitGoogleLogging#google##YAXPBD#Z) が関数 _main で参照されました。
1>main.obj : error LNK2019: 未解決の外部シンボル "public: __thiscall google::LogMessage::LogMessage(char const *,int)" (??0LogMessage#google##QAE#PBDH#Z) が関数 _main で参照されました。
1>main.obj : error LNK2019: 未解決の外部シンボル "public: __thiscall google::LogMessage::~LogMessage(void)" (??1LogMessage#google##QAE#XZ) が関数 _main で参照されました。
I'm compiling as Win32.
If I check the debug folder it actually contains the dll+lib or static lib file.
I also tried linking to the library manually without using the visual studio dependency system, but it's the same.
I've built glog for MSVS2012 from trunk (little patch mentioned in header already presented here, as i know), so it works for me.
Looks like your dependency description of glog library is missing.
Can you add windows-specific
#pragma comment(lib, "path_to_glog_from_project_dir.lib")
to one of your project files, for example, directly into main.cpp and test it.
I just have a problem that I have been trying to fix for the longest time.
I have a static library project in visual c++, and I want another project to be able to link to it. Up until now, I have simply been adding a reference to the static library project, which automatically links the library.
I want to be able to link to the library using only the header files and the .lib file. However, I get a "Unresolved external symbol" error.
I thought I was doing it right - I specified the include directory, the library directory, and went into the linker input properties and provided the lib as an additional dependency.
I am able to reference other static libraries this way (like SDL), so why do I get errors when I try to reference mine?
Thanks for the help.
Is the problem that its not referencing the actual lib file, or is something within the lib itself?
These are the error messages I get:
Error 2 error LNK2019: unresolved external symbol "public: void __thiscall XEngine::XCore::XScreen::init(class XEngine::XCore::XGame &)" (?init#XScreen#XCore#XEngine##QAEXAAVXGame#23##Z) referenced in function "void __cdecl XEngine::XEngineInit(class XEngine::XCore::XScreen &,class XEngine::XCore::XGame &)" (?XEngineInit#XEngine##YAXAAVXScreen#XCore#1#AAVXGame#31##Z) C:\Users\Xander Masotto\Documents\Visual Studio 2010\Projects\Pong\Pong\source.obj Pong
Error 3 error LNK2019: unresolved external symbol "public: __thiscall XEngine::XCore::XScreen::~XScreen(void)" (??1XScreen#XCore#XEngine##QAE#XZ) referenced in function "void __cdecl XEngine::XEngineInit(class XEngine::XCore::XGame &)" (?XEngineInit#XEngine##YAXAAVXGame#XCore#1##Z) C:\Users\Xander Masotto\Documents\Visual Studio 2010\Projects\Pong\Pong\source.obj Pong
Error 4 error LNK2019: unresolved external symbol "public: __thiscall XEngine::XCore::XScreen::XScreen(void)" (??0XScreen#XCore#XEngine##QAE#XZ) referenced in function "void __cdecl XEngine::XEngineInit(class XEngine::XCore::XGame &)" (?XEngineInit#XEngine##YAXAAVXGame#XCore#1##Z) C:\Users\Xander Masotto\Documents\Visual Studio 2010\Projects\Pong\Pong\source.obj Pong
Make sure that you are exporting the functions, classes, and variables in your library that you want exposed to other applications (i.e. your dll or exe). By default they are not exposed.
The ground work to do this is typically layed out when you create the project for your library.
#ifdef TESTLIB_EXPORTS
#define TESTLIB_API __declspec(dllexport)
#else
#define TESTLIB_API __declspec(dllimport)
#endif
With the code above generated during project creation there are only two more things for me to do to expose functions,classes, or variables:
1) Make sure that I have TESTLIB_EXPORTS defined as a preprocessor. Project settings: C++/Preprocessor/PreprocessorDefinitions
2) Use the TESTLIB_API define on each function,class, or variable i want exposed:
class TESTLIB_API Order {
void doSomething();
};
I'm back to C/C++ after some break.
I've a following problem:
I've a solution where I've several projects (compilable and linkable).
Now I need to add another project to this solution which depends on some sources from other projects.
My new project compiles without any problems (I've added "existing sources" to my project).
the error:
1>Linking...
1>LicenceManager.obj : error LNK2019: unresolved external symbol "int __cdecl saveLic(char *,struct Auth *)" (?saveLic##YAHPADPAUAuth###Z) referenced in function "public: void __thiscall LicenceManager::generateLicence(int,char *)" (?generateLicence#LicenceManager##QAEXHPAD#Z)
1>LicenceManager.obj : error LNK2019: unresolved external symbol "void __cdecl getSysInfo(struct Auth *)" (?getSysInfo##YAXPAUAuth###Z) referenced in function "public: void __thiscall LicenceManager::generateLicence(int,char *)" (?generateLicence#LicenceManager##QAEXHPAD#Z)
Functions saveLic, and getSysInfo are defined in files which I've added to my new project from existing ones. There is object file created during compilation with those functions in target dir, but my LicenceManager class doesn't want to link.
I use some
extern "C" , and #pragma pack
somewhere, but no more fancy stuff. I think every directory, lib and other necessary dependencies are visible in settings for this project.
Thanks for any advice.
Seems like you need to make sure the functions are declared properly as C functions:
#ifdef __cplusplus
extern "C" {
#endif
int saveLic(char *,struct Auth *);
void getSysInfo(struct Auth *);
#ifdef __cplusplus
}
#endif
In a header file included by LicenceManager.cpp.