1

我正在第一次尝试用 C++ 进行单元测试,而且我已经很多年没有使用过 C++(我目前主要是 C# 编码器)。看来我正在做一个正确的猪耳朵 - 我希望有人能引导我回到正义的道路上。我刚从这里开始,并且真的很想使用可能的最佳实践来实现这些测试,所以欢迎任何和所有评论,即使我目前最关心我的链接器错误。

所以,我有一个整体解决方案“Technorabble”,子项目“CalibrationTool”和“CalibrationToolUnitTests”。

CalibrationTool 有一个 MathUtils.h 文件:

#ifndef __math_utils__
#define __math_utils__

#include "stdafx.h"
#include <vector>

namespace Technorabble
{
    namespace CalibrationTool
    {
        double GetDoubleVectorAverage(std::vector<double> v)
        {
            double cumulativeValue = 0;
            for(std::vector<double>::iterator iter = v.begin(); iter != v.end(); ++iter) 
            {
                cumulativeValue += *iter;
            }
            return cumulativeValue / v.size();
        }
    }; // end namespace CalibrationTool
};  // end namespace Technorabble

#endif // !__math_utils__

(但没有 .cpp 文件,因为我遇到了各种(有点相似)问题,让我的模板函数正常工作 - 所以我最终定义了那个内联)。

继续进行单元测试项目,我有一个 main.cpp:

#include "MathUtilsTest.h"

void RunMathUtilsTests();

int main()
{
    RunMathUtilsTests();

    // Other class tests will go here when I have things to test
}

void RunMathUtilsTests()
{
    MathUtilsTest* mathUtilsTest = new MathUtilsTest();
    mathUtilsTest->RunTests();
    delete mathUtilsTest;
}

最后,MathUtilsTest 类的头文件和 cpp,同样非常简单:

。H:

#ifndef __MATH_UTILS_TEST__
#define __MATH_UTILS_TEST__

#include "CalibrationToolUnitTestsLogging.h"
#include "..\CalibrationTool\MathUtils.h"

class MathUtilsTest
{
public:
    MathUtilsTest();
    ~MathUtilsTest();

     bool RunTests();

private:    
    bool GetDoubleVectorAverageTest();

}; // end class MathUtilsTest

#endif

.cpp:

#include "MathUtilsTest.h"
#include <sstream>

bool MathUtilsTest::RunTests()
{
    return GetDoubleVectorAverageTest();

}

MathUtilsTest::~MathUtilsTest()
{

}

MathUtilsTest::MathUtilsTest()
{

}

bool MathUtilsTest::GetDoubleVectorAverageTest()
{
    bool passed = true;
    std::vector<double> values;
    for (int i = 1; i < 23; i++)
    {
        values.push_back(i);
    }
    // vector becomes: 1, 2, 3, 4, .....20, 21, 22.  Average is 11.5
    double expectedAverage = 11.5;
    double calculatedAverage = Technorabble::CalibrationTool::GetDoubleVectorAverage(values);
    if (calculatedAverage != expectedAverage)
    {
        std::ostringstream s;
        s << calculatedAverage;
        std::string avgString = s.str();
        CalibrationToolUnitTestsLogging::Write("Failed MathUtilsTest.GetDoubleVectorAverageTest:  " + avgString);
        passed = false;
    }
    else
    {
        CalibrationToolUnitTestsLogging::Write("Passed MathUtilsTest.GetDoubleVectorAverageTest");
    }

    return passed;
}

这一切对我来说似乎都很好,我正在用#ifndef 等保护我的标题。但我仍然收到以下错误:

1) 错误 LNK1169:找到一个或多个多重定义符号

2) 错误 LNK2005: "double __cdecl Technorabble::CalibrationTool::GetDoubleVectorAverage(class std::vector >)" (?GetDoubleVectorAverage@CalibrationTool@Technorabble@@YANV?$vector@NV?$allocator@N@std@@@std @@@Z) 已在 main.obj C:_SVN\Technorabble\Windows Software\CalibrationToolUnitTests\MathUtilsTest.obj 中定义

怎么会这样?谁能发现哪里出错了?

4

2 回答 2

5

标题中定义的函数应标记为inline

inline double GetDoubleVectorAverage(std::vector<double> v)
{
}

如果它超过几行,请考虑将其移至实现文件。

pragmas 或 include 守卫不能防止多重定义。

请注意,您应该通过v引用const而不是按值传递。

于 2013-09-17T14:28:24.463 回答
3

您正在GetDoubleVectorAverage标题中定义一个函数。这意味着它将在包含该标题的每个翻译单元(即每个源文件)中定义。如果您的程序包含多个这样的翻译单元,那么您将有多个定义 - 这是不允许的。

解决方案是:

  • 增加inline函数定义,放宽这个规则,允许多个相同的定义;或者
  • 将函数定义移动到源文件中,并且只在头文件中声明它。

我正在保护我的标题#ifndef

这只防止标题在同一个翻译单元中被多次包含。它不会阻止包含多个单元。

此外,您不应该使用保留名称__math_utils__作为标头保护,即使互联网上充斥着这样做的狡猾代码的示例。

我遇到了各种各样(有点相似)的问题,让我的模板功能正常工作

模板通常需要在头文件中定义,以使定义在使用时可用。函数模板是隐式的inline,但普通函数(比如这个)不是。

于 2013-09-17T14:28:55.417 回答