17

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?

Justin R.
  • 23,435
  • 23
  • 108
  • 157
Pieter
  • 31,619
  • 76
  • 167
  • 242
  • 1
    No, that means that **linker** doesn't find the binaries containing your referenced symbols. – SomeWittyUsername Dec 23 '12 at 11:38
  • Right, how do I tell the linker where to find the required files? I already tried [this](http://i.imgur.com/jitTd.png) without success. – Pieter Dec 23 '12 at 13:06
  • That should do the trick. Also make sure you *really* compile all the projects containing your files (check the dependencies) – SomeWittyUsername Dec 23 '12 at 13:30
  • Sadly I'm still getting the errors, even after cleaning and rebuilding both projects in order. I also tried using `$(SolutionDir)\Cubes\Debug` instead, which appears to store the `.obj` files. I come from a MinGW background, so I'm used to source code compiling as `.o` files. – Pieter Dec 23 '12 at 15:05
  • Check the Linker->Input->Additional Dependencies. Add your `.lib` files there manually – SomeWittyUsername Dec 23 '12 at 17:36
  • I can't find any `.lib` files in the main project folder. Are they supposed to be there? Do I have to change the property sheets of my main project to generate them? My main project generates an `.exe` and according to [other threads](http://stackoverflow.com/questions/2658215/how-do-i-create-both-a-lib-file-and-an-exe-file-in-visual-c) you can't make `.exe` and `.lib` files at the same time. – Pieter Dec 23 '12 at 20:09
  • you should change your main project target to `.lib` and in UT project add reference to it like I wrote above – SomeWittyUsername Dec 23 '12 at 20:31
  • But I need that `.exe`. There's gotta be a better way to create unit tests. I've worked with JUnit before and that worked pretty much out of the box. Are there any Visual Studio plugins or other tools you'd recommend? – Pieter Dec 24 '12 at 10:29
  • What I mean is that in multi-project solution, one of the projects is the startup project (this one should be targeted as `.exe`) and rest should be targeted as `.lib` binaries which are linked along with the startup project to form the `.exe`. In your case the startup is the `UT` project so rest of the projects should be converted to `.lib` targets. I don't know if MS has made some kind of automation specifically for `UT` to skip all these steps, but in general this are the required adjustments – SomeWittyUsername Dec 24 '12 at 11:10
  • @fatcat1111: See answer below... – Jochen Kalmbach Jul 22 '13 at 10:05

1 Answers1

15

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

  1. Create a Win32 Application (Console or MFC or Windows, does not matter); I created a console project called CPP_UnitTestApp:

  2. Add a function you want to test (you can also add classes). For example:

    int Plus1(int i)
    {
      return i+1;
    }
    
  3. Add a header file for the functions you want to test: CPP_UnitTestApp.h

  4. 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);
    
  5. 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"
    
  6. Now add a new project (Native unit test project: UnitTest1)

  7. 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")
    
  8. 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)

  9. Create the unit test function:

    TEST_METHOD(TestMethod1)
    {
      int res = Plus1(12);
      Assert::AreEqual(13, res);
    }
    
  10. 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

manuel
  • 533
  • 6
  • 16
Jochen Kalmbach
  • 3,549
  • 17
  • 18