使用Visual Studio C++进行单元测试时出现链接器错误

7

我想使用Visual Studio对我的C++项目进行单元测试。将我的项目文件夹添加为测试项目的包含路径后,在尝试编译测试时出现了链接错误:

Severity    Code    Description Project File    Line    Suppression State
Error   LNK2019 unresolved external symbol "public: __thiscall Piece::Piece(enum Color)" (??0Piece@@QAE@W4Color@@@Z) referenced in function "public: __thiscall Bishop::Bishop(enum Color)" (??0Bishop@@QAE@W4Color@@@Z)    ChessPlusPlus-Tests D:\Documents\Projects\ChessPlusPlus\ChessPlusPlus-Tests\BishopTests.obj 1   
Error   LNK2019 unresolved external symbol "public: __thiscall Board::~Board(void)" (??1Board@@QAE@XZ) referenced in function "public: void __thiscall ChessPlusPlusTests::BishopTests::ValidMovesTest(void)" (?ValidMovesTest@BishopTests@ChessPlusPlusTests@@QAEXXZ)  ChessPlusPlus-Tests D:\Documents\Projects\ChessPlusPlus\ChessPlusPlus-Tests\BishopTests.obj 1   
Error   LNK2019 unresolved external symbol "public: void __thiscall Board::placePieceAt(class Piece * const,struct Position)" (?placePieceAt@Board@@QAEXQAVPiece@@UPosition@@@Z) referenced in function "public: void __thiscall ChessPlusPlusTests::BishopTests::ValidMovesTest(void)" (?ValidMovesTest@BishopTests@ChessPlusPlusTests@@QAEXXZ)    ChessPlusPlus-Tests D:\Documents\Projects\ChessPlusPlus\ChessPlusPlus-Tests\BishopTests.obj 1   
Error   LNK2001 unresolved external symbol "public: virtual class std::vector<struct Position,class std::allocator<struct Position> > __thiscall Bishop::getMovesFor(struct Position,class Board &)" (?getMovesFor@Bishop@@UAE?AV?$vector@UPosition@@V?$allocator@UPosition@@@std@@@std@@UPosition@@AAVBoard@@@Z)   ChessPlusPlus-Tests D:\Documents\Projects\ChessPlusPlus\ChessPlusPlus-Tests\BishopTests.obj 1   
Error   LNK2001 unresolved external symbol "public: virtual class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __thiscall Bishop::toString(void)" (?toString@Bishop@@UAE?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ)    ChessPlusPlus-Tests D:\Documents\Projects\ChessPlusPlus\ChessPlusPlus-Tests\BishopTests.obj 1   
Error   LNK2001 unresolved external symbol "public: virtual class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > __thiscall Bishop::toShortString(void)" (?toShortString@Bishop@@UAE?AV?$basic_string@DU?$char_traits@D@std@@V?$allocator@D@2@@std@@XZ)  ChessPlusPlus-Tests D:\Documents\Projects\ChessPlusPlus\ChessPlusPlus-Tests\BishopTests.obj 1   

我的测试源代码:

#include "stdafx.h"
#include "CppUnitTest.h"
#include "Bishop.h"
#include "Board.h"
#include "TestUtils.h"

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace ChessPlusPlusTests
{
    TEST_CLASS(BishopTests)
    {
    public:

        TEST_METHOD(ValidMovesTest)
        {
            // Arrange
            Board board{};
            Bishop *piece = new Bishop{ Color::WHITE };
            Position pos{ 3,3 };
            board.placePieceAt(piece, pos);

            // Act
            auto validPositions = piece->getMovesFor(pos, board);

            // Assert
            TestUtils::AssertPositions(validPositions, {
                0,0,0,0,0,0,0,1,
                1,0,0,0,0,0,1,0,
                0,1,0,0,0,1,0,0,
                0,0,1,0,1,0,0,0,
                0,0,0,0,0,0,0,0,
                0,0,1,0,1,0,0,0,
                0,1,0,0,0,1,0,0,
                1,0,0,0,0,0,1,0,
            });
        }

    };
}

如果不添加包含路径,测试项目将无法编译,因为头文件中的包含依赖于主项目中的包含路径。

主项目可以正常编译。

有人能帮我理解出了什么问题吗?

谢谢!


你在项目属性中添加了静态库及其路径吗? - Pavan Chandaka
我不确定你的意思。我将主项目添加为测试项目的引用,并且只使用标准库。 - David Speck
3个回答

18
我认为所选答案不正确。测试通常应该在它们的环境中运行;因此,它们不应访问实现 (.cpp)。
当您在Visual Studio (VS 2017)上创建一个单独的测试项目时,您需要创建对要测试的项目的引用(右键单击测试项目 -> 添加 -> 引用 -> 选中项目):添加引用 如果您看到一些链接器错误,请从单元测试项目右键单击:项目-> 链接器 -> 输入 -> 其他依赖项 -> 编辑,然后添加到.obj文件的路径。 您可以尝试像 "$(SolutionDir)ConsoleApplication1\$(IntDir)*.obj" 这样的东西,其中 ConsoleApplication1 是目标项目名称。 . obj文件路径 起初,我只想在 Cornelis 的帖子上发表评论,但我无法这样做。

1
我不知道为什么这个没有被点赞。显然这是最理想的解决方案,而且我在微软官方博客中也没有找到提到过。他们只是简单地说要添加对现有项目的引用,依赖项就会自动配置,但实际上并非如此,并且他们也没有继续使用目标项目中的函数编写测试。 - sz ppeter
1
这个工作异常出色。你有没有想法,这是否是正确的方法?它似乎相当hack-y。添加一个引用不应该解决这个问题吗? - mortom123
这是正确的方法。添加一个引用可能就足够了,但如果不行,你必须手动指定一些引用。 - Patrice Thimothee
警告:添加$(IntDir).obj可能会添加不需要的带有main()函数的.obj文件,这将完全阻止测试发现!详细信息在此处 - undefined

2

非常感谢您!许多来源都建议将我的项目转换为dll或其他什么东西,而您在这里提供了最简单的解决方案。 - gameCoder95

2
我遇到了相同的问题,但是通过这篇微软文档以不同的方式解决了它:https://learn.microsoft.com/nl-nl/visualstudio/test/unit-testing-existing-cpp-applications-with-test-explorer?view=vs-2015&redirectedfrom=MSDN#objectRef
我认为这个解决方案更加简洁,因为您不需要在测试项目中显示您的被测试项目中的所有头文件。
以下是来自文档的斜体行,粗体行是我的补充:
如果要测试的代码未导出所需的函数,则可以将输出的.obj或.lib文件添加到测试项目的依赖项中。
创建一个C++测试项目。
在“文件”菜单上,选择“新建”,“项目”,“Visual C++”,“测试”,“C++单元测试项目”。 确保将要测试的项目添加为引用。如果忘记了,也可以稍后在“解决方案资源管理器”窗口中添加这些引用。 在“解决方案资源管理器”中,在测试项目的快捷菜单上,选择“属性”。打开项目属性窗口。
选择“配置属性”,“链接器”,“输入”,“附加依赖项”。
选择“编辑”,并添加.obj或.lib文件的名称。不要使用完整的路径名。 对我来说,只有.obj文件。我在中间文件夹中找到了它们,其中有多个版本,每个版本都有一个解决方案平台(x86或x64)和解决方案配置(Debug或Release)的组合。如果您有很多.obj(或.lib)文件,则我发现在终端上运行ls(或dir)以获取文件名并编辑出不需要的.log、.txt和.pdb文件名,然后将.obj文件名列表复制粘贴到Visual Studio中非常方便。请注意,您可以单击附加依赖项条目字段右侧的下拉箭头并单击“编辑”进行方便的编辑。 选择“配置属性”,“链接器”,“常规”,“附加库目录”。
选择“编辑”,并添加.obj或.lib文件的目录路径。该路径通常位于被测试项目的构建文件夹内。
对我来说,我只有.obj文件。我在中间文件夹中找到了它们,其中有多个版本,每个版本都有一个解决方案平台(x86或x64)和解决方案配置(Debug或Release)的组合。设置所有4个组合的路径的便捷宏是:$(SolutionDir)bin\$(PlatformTarget)\$(IntermediateOutputPath)Intermediates。您可能需要删除bin\部分,因为我还看到过将输出文件夹直接设置在解决方案目录中,而不是在单独的二进制文件夹中。
选择“配置属性”、“VC++目录”、“包含目录”。
选择“编辑”,然后添加要测试的项目的头文件目录。
对于这个目录,可以直接指向测试项目的一部分文件夹,而不需要复制头文件到测试项目中。如果这个目录包含更多的内容,也不会有问题。例如,我的源文件夹包含.h文件和.cpp文件。
按照这些步骤后,我能够通过简单地编写以下内容在我的测试代码中包含头文件:
#include "SomeHeaderName.h"
所以,无需指定头文件所在的文件夹。
确保清理并重新构建整个解决方案。然后,您的测试应该能够访问您正在测试的项目的功能。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接