在单元测试项目中包括.c文件,并可以从多个cpp文件访问它,而无需链接问题

时间:2018-06-20 11:39:01

标签: c++ c unit-testing

我正在对C代码进行功能测试。到目前为止,在测试.cpp文件中已包含.c文件,一切正常。但是我需要在另一个进行其他单元测试的.cpp文件中包含相同的.c文件。然后我得到已经定义的问题。因为我已经将它包含在第一个文件cpp中。

如果将所有测试方法合并到一个cpp文件中,则它将很好地工作。如果将所有单元测试都放在一个文件中,那么我需要在同一项目中拆分不同的文件,它还会创建帮助函数以确保将函数放入胶囊中。

这不是正常的LNK2005,因为我无法在.h中声明变量和函数:extern BOOL MyBool;。然后将其分配给.c或.cpp文件。因为我需要对c文件进行单元测试才能使用此功能。我也不能或应该避免进行任何更改。c。

我正在寻找保留.c local的方法,而不会影响同一项目中的其他文件。

source.h

#ifndef SOURCE_H_
#define SOURCE_H_

#include "../car.h"

enum INITIALMODE {
   INITIALMODE_NOT_POSITIONING,             // 0
   INITIALMODE_NO_DRIVER_INPUT,             // 1
   INITIALMODE_POSITION_LOW_POSITION,       // 2
   INITIALMODE_POSITION_STANDARD_POSITION,  // 3
   INITIALMODE_POSITION_HIGH_POSITION       // 4
};
void initMotor(void);
#endif

source.c

/* Compiler include files */
#pragma once

#include "positioning.h"
#include "api.h"
#include "drive.h"
#include "types.h"

static void updateTarget(void);
static SWord getMax(UWord Limit, UWord Aux);
static DWord getHeight(void);
static Bool isMode(void);
static Bool isExiting(void);

#define cMaxHeight      100 * Profile.s.Max /* m -> mm */

void initMotor(void)
{
   // do something
}

static void updatePositioning(void)
{
   // do something
}

测试文件看起来像这样,但是,它的规模非常小,可以缩小示例范围。

UnitTest.cpp UnitTest2.cpp

#include "CppUnitTest.h"

#ifndef UNIT_TEST
#define UNIT_TEST

using namespace Microsoft::VisualStudio::CppUnitTestFramework;

namespace Test
{

    extern "C" {
     #include "../../Test/source.h"
     #include "../../Test/source.c"
    }

TEST_CLASS(UnitTest_1)
{
public:

    TEST_METHOD(Test_1)
    {
        // Verify that the initial state is as expected.
        initTest();

        //Expected value
        UWord Expected = 500
        //Trigger to execute.
        UWord Test = updatePositioning();

        // Verify that the results are as expected.
        Assert::AreEqual(Expected, Test);

      }
   };
}
#endif

1 个答案:

答案 0 :(得分:1)

您永远不应包含.C或.CPP文件。

但是,您可以用C ++编译C代码。这是一个基于您在初始帖子中提供的信息的示例。

YourCCode.h

#ifndef YourCCode_H
#define YourCCode_H

int FunctionToTest(int SomeParams);

int TestStaticFunctions(int SomeParam1, int SomeParam2);

#endif // YourCCode_H

YourCCode.c

#include "YourCCode.h"

static int SomeStaticFunction(int Param1, int Param2)
{
  return Param1 + Param2; // that needs extensive testing, obviously.
}

int FunctionToTest(int SomeParams)
{
  return SomeStaticFunction(SomeParams, 1); 
}

int TestStaticFunctions(int SomeParam1, int SomeParam2)
{
  return SomeStaticFunction(SomeParam1, SomeParam2);
}

UnitTest1.cpp

extern "C" {
#include "YourCCode.h"
}

bool TestFunction(int Value)
{
  return (FunctionToTest(Value) == Value+1);
}

UnitTest2.cpp

extern "C" {
#include "YourCCode.h"
}

void AnotherTestFunction(int Val, int Val2)
{
  int newValue = TestStaticFunctions(Val, Val2);
  ASSERT(newValue == Val+Val2);
}

然后编译您的CPP和C文件。


在澄清了意图之后,我意识到您正在尝试从另一个单元测试静态函数。根据定义,静态功能仅可用于同一翻译单元中的其他功能。这主要是用于防止程序员在不知道如何验证其输入,不知道调用顺序等情况下调用某些函数的保护措施。

在这里,我最好的选择是要么选择功能不是静态的,然后就可以在翻译单元外部对其进行测试,要么在包含这些静态函数的翻译单元内部实现测试功能。我建议后者,因为翻译部门应该(从体系结构上来说)知道如何测试自己的功能。


作为第三种解决方案,如果您对C文件的内容没有任何控制权(但是由于您拥有C文件,我对此表示怀疑),则可以使用包含C文件的代理CPP文件,并为每个静态呼叫创建一个代理呼叫。

但是,这是一个丑陋的破解,如果C文件得到更新,很可能会很容易破解,所以我建议不要这样做。

这是一个简单的例子:

YourCCode.h

#ifndef YourCCode_H
#define YourCCode_H

void SomeFunction(void);

#endif // YourCCode_H

YourCCode.c

#include "YourCCode.h"

static int AddSomething(int Param1, int Param2)
{
  return Param1 + Param2;
}

static int SubtractSomething(int Param1, int Param2)
{
  return Param1 - Param2;
}

void SomeFunction(void)
{
  // code meant to be called externally.
}

ProxyTestCode.hpp

bool TestAddSomething(void);
bool TestSubtractSomething(void);

ProxyTestCode.cpp

extern "C" {
#include "YourCCode.h"
#include "YourCCode.c"
}

bool TestAddSomething(void)
{
  return (AddSomething(2,2) == 4);
}

bool TestSubtractSomething(void)
{
  return (AddSomething(2,2) == 0);
}

UnitTest1.cpp

#include "ProxyTestCode.hpp"

void TestAdd(void)
{
  ASSERT(TestAddSomething());
}

UnitTest2.cpp

#include "ProxyTestCode.hpp"

void TestSubtract(void)
{
  ASSERT(TestSubtractSomething());
}

如果这样做,不要在项目中编译C文件。