As far as I understand it, I can simply place catch.hpp
into my project directory, add it to the project, and then start writing tests. I'm running into a few, or 11 to be exact, linker errors once I try using some of the macros outlined in the tutorial.
#include "catch.hpp"
unsigned int Factorial( unsigned int number ) {
return number <= 1 ? number : Factorial(number-1)*number;
}
TEST_CASE( "Factorials are computed", "[factorial]" ) {
REQUIRE( Factorial(1) == 1 );
REQUIRE( Factorial(2) == 2 );
REQUIRE( Factorial(3) == 6 );
REQUIRE( Factorial(10) == 3628800 );
}
I'm able to create a single file out of the first example and compile it with g++, but when I just paste the same code into my VS2010 project and then try to run it, I run into the linker errors. Unfortunately I'm not familiar enough with C++ at this point to decode the errors myself, and after taking a look at the single file here, I was unable to discern the issue.
Error 1 error LNK2019: unresolved external symbol "public: __thiscall Catch::AutoReg::AutoReg(void (__cdecl*)(void),struct Catch::SourceLineInfo const &,struct Catch::NameAndDesc const &)" (??0AutoReg@Catch@@QAE@P6AXXZABUSourceLineInfo@1@ABUNameAndDesc@1@@Z) referenced in function "void __cdecl `anonymous namespace'::`dynamic initializer for 'autoRegistrar27''(void)" (??__EautoRegistrar27@?A0x3911e331@@YAXXZ) C:\Users\Mark\documents\visual studio 2010\Projects\FirstCPPApplication\FirstCPPApplication\FirstCPPApplication.obj 1 1 FirstCPPApplication
Error 2 error LNK2019: unresolved external symbol "public: __thiscall Catch::ExpressionResultBuilder::ExpressionResultBuilder(enum Catch::ResultWas::OfType)" (??0ExpressionResultBuilder@Catch@@QAE@W4OfType@ResultWas@1@@Z) referenced in function __catch$?____C_A_T_C_H____T_E_S_T____27@@YAXXZ$0 C:\Users\Mark\documents\visual studio 2010\Projects\FirstCPPApplication\FirstCPPApplication\FirstCPPApplication.obj 1 1 FirstCPPApplication
Error 3 error LNK2019: unresolved external symbol "class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __cdecl Catch::translateActiveException(void)" (?translateActiveException@Catch@@YA?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ) referenced in function __catch$?____C_A_T_C_H____T_E_S_T____27@@YAXXZ$0 C:\Users\Mark\documents\visual studio 2010\Projects\FirstCPPApplication\FirstCPPApplication\FirstCPPApplication.obj 1 1 FirstCPPApplication
Error 4 error LNK2019: unresolved external symbol "public: class Catch::ExpressionResultBuilder & __thiscall Catch::ExpressionResultBuilder::endExpression(enum Catch::ResultDisposition::Flags)" (?endExpression@ExpressionResultBuilder@Catch@@QAEAAV12@W4Flags@ResultDisposition@2@@Z) referenced in function "void __cdecl ____C_A_T_C_H____T_E_S_T____27(void)" (?____C_A_T_C_H____T_E_S_T____27@@YAXXZ) C:\Users\Mark\documents\visual studio 2010\Projects\FirstCPPApplication\FirstCPPApplication\FirstCPPApplication.obj 1 1 FirstCPPApplication
Error 5 error LNK2019: unresolved external symbol "public: __thiscall Catch::AssertionInfo::AssertionInfo(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,struct Catch::SourceLineInfo const &,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &,enum Catch::ResultDisposition::Flags)" (??0AssertionInfo@Catch@@QAE@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@ABUSourceLineInfo@1@0W4Flags@ResultDisposition@1@@Z) referenced in function "void __cdecl ____C_A_T_C_H____T_E_S_T____27(void)" (?____C_A_T_C_H____T_E_S_T____27@@YAXXZ) C:\Users\Mark\documents\visual studio 2010\Projects\FirstCPPApplication\FirstCPPApplication\FirstCPPApplication.obj 1 1 FirstCPPApplication
Error 6 error LNK2019: unresolved external symbol "struct Catch::IContext & __cdecl Catch::getCurrentContext(void)" (?getCurrentContext@Catch@@YAAAUIContext@1@XZ) referenced in function "struct Catch::IResultCapture & __cdecl Catch::getResultCapture(void)" (?getResultCapture@Catch@@YAAAUIResultCapture@1@XZ) C:\Users\Mark\documents\visual studio 2010\Projects\FirstCPPApplication\FirstCPPApplication\FirstCPPApplication.obj 1 1 FirstCPPApplication
Error 7 error LNK2019: unresolved external symbol "public: class Catch::ExpressionResultBuilder & __thiscall Catch::ExpressionResultBuilder::setOp(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &)" (?setOp@ExpressionResultBuilder@Catch@@QAEAAV12@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) referenced in function "private: class Catch::ExpressionResultBuilder & __thiscall Catch::ExpressionLhs<int const &>::captureExpression<0,int>(int const &)" (??$captureExpression@$0A@H@?$ExpressionLhs@ABH@Catch@@AAEAAVExpressionResultBuilder@1@ABH@Z) C:\Users\Mark\documents\visual studio 2010\Projects\FirstCPPApplication\FirstCPPApplication\FirstCPPApplication.obj 1 1 FirstCPPApplication
Error 8 error LNK2019: unresolved external symbol "public: class Catch::ExpressionResultBuilder & __thiscall Catch::ExpressionResultBuilder::setRhs(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &)" (?setRhs@ExpressionResultBuilder@Catch@@QAEAAV12@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) referenced in function "private: class Catch::ExpressionResultBuilder & __thiscall Catch::ExpressionLhs<int const &>::captureExpression<0,int>(int const &)" (??$captureExpression@$0A@H@?$ExpressionLhs@ABH@Catch@@AAEAAVExpressionResultBuilder@1@ABH@Z) C:\Users\Mark\documents\visual studio 2010\Projects\FirstCPPApplication\FirstCPPApplication\FirstCPPApplication.obj 1 1 FirstCPPApplication
Error 9 error LNK2019: unresolved external symbol "public: class Catch::ExpressionResultBuilder & __thiscall Catch::ExpressionResultBuilder::setLhs(class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > const &)" (?setLhs@ExpressionResultBuilder@Catch@@QAEAAV12@ABV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@@Z) referenced in function "private: class Catch::ExpressionResultBuilder & __thiscall Catch::ExpressionLhs<int const &>::captureExpression<0,int>(int const &)" (??$captureExpression@$0A@H@?$ExpressionLhs@ABH@Catch@@AAEAAVExpressionResultBuilder@1@ABH@Z) C:\Users\Mark\documents\visual studio 2010\Projects\FirstCPPApplication\FirstCPPApplication\FirstCPPApplication.obj 1 1 FirstCPPApplication
Error 10 error LNK2019: unresolved external symbol "public: class Catch::ExpressionResultBuilder & __thiscall Catch::ExpressionResultBuilder::setResultType(bool)" (?setResultType@ExpressionResultBuilder@Catch@@QAEAAV12@_N@Z) referenced in function "private: class Catch::ExpressionResultBuilder & __thiscall Catch::ExpressionLhs<int const &>::captureExpression<0,int>(int const &)" (??$captureExpression@$0A@H@?$ExpressionLhs@ABH@Catch@@AAEAAVExpressionResultBuilder@1@ABH@Z) C:\Users\Mark\documents\visual studio 2010\Projects\FirstCPPApplication\FirstCPPApplication\FirstCPPApplication.obj 1 1 FirstCPPApplication
Error 11 error LNK2019: unresolved external symbol "public: __thiscall Catch::AutoReg::~AutoReg(void)" (??1AutoReg@Catch@@QAE@XZ) referenced in function "void __cdecl `anonymous namespace'::`dynamic atexit destructor for 'autoRegistrar27''(void)" (??__FautoRegistrar27@?A0x3911e331@@YAXXZ) C:\Users\Mark\documents\visual studio 2010\Projects\FirstCPPApplication\FirstCPPApplication\FirstCPPApplication.obj 1 1 FirstCPPApplication
Error 12 error LNK1120: 11 unresolved externals C:\Users\Mark\documents\visual studio 2010\Projects\FirstCPPApplication\Debug\FirstCPPApplication.exe FirstCPPApplication
Test shortcuts Tests can be run from Test Explorer by right-clicking in the code editor on a test and selecting Run test or by using the default Test Explorer shortcuts in Visual Studio.
On the File menu, select New > Project, or press Ctrl+Shift+N. On the Create a new project page, type unit test into the search box. Select the project template for the test framework that you want to use, for example MSTest Test Project or NUnit Test Project, and then select Next.
long story short: split your single project solution into 3, use a .lib
of the old exe
, add the projects to the appropriate paths, update the linker, and you're good to go.
AE Drew's answer helped solve my problem, but I want to put a more full solution to the question's title, in case anyone's coming from Google, especially if they are looking for a simple breakdown from a beginner's perspective.
If you only had one project in your solution that built a .exe
for you, CATCH
wouldn't work: your solution needs 3 projects (as far as I know) to be able to
test your code.
Source_project
, The main codebase project (in which the source code for
your application resides)
Test_project
, The test suites project (in which the REQUIRES
tests appear
as outlined in the above question)
Main_project
, The project where you actually call and run the code from the
source codebase.
In order to convert your original single-project solution into something that
you can use in both tests and to properly run, you'll need to build a .lib
or
a .dll
so that other projects (including other people's projects) can use the
same code. Altering this answer, all it takes is to
right-click on your project in the Solution Explorer, and select > Properties.... Under Configuration Properties -> General there's an > option called Configuration Type. If you change it to [Static Library > (.lib)], your project will generate a [
.lib
] when it is built.
And then in the 3rd project, main_project
, where you have a barebones setup
from a Win32 Console Application that only contains a file that looks something
like:
#include "stdafx.h"
#include "HEADER_FROM_FIRST_PROJECT.h"
int _tmain(int argc, _TCHAR* argv[])
{
METHOD_FROM_FIRST_PROJECT();
return 0;
}
where you import a header file from Source_project
, the first project that we
created (the one that used to be an exe
, but is now building to a lib
). But
that's not going to run yet, you need to add the Source_project
's directory to
this projects additional directories, by right clicking the project in the
Solution Explorer, under Properties > Configuration Properties > C/C++ > General >
Additional Include Directories, add the source_project
's folder to the list. This'll
allow the #include
lines to automatically search that directory for the appropriate
files, saving you from having to write ../source_project/HEADER_FROM_FIRST_PROJECT.h
.
Finally, the last step is to make sure that the linker will be able to actually
find the objects that you are trying to include. And since we're building a
.lib
, we're able to do this rather simply. In the same settings dialog box as
before, the Projects Properties dialog, we'll navigate instead to Configuration
Properties > Linker > Input > Additional Dependencies and add the relative path to the
source_project.lib
file, which would look something like ../Debug/source_project.lib
.
Note that if you have any .dll
s that are in the old exe
project, it'll
need to be moved into the new main_project
.
Also note that this is all very new to me and some of the terms and information are bound to be incorrect.
Just scanning through the links you provide, I think you may need to add this line at the top of your file.
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() - only do this in one cpp file
It looks like the functions you are trying to link are within #if defined CATCH_CONFIG_MAIN .... #endif
preprocessor directives.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With