[英]Testing templated classes with functions defined in CPP file
For a project that I am working on, I need to mock certain classes for testing to test different behaviours of functions.对于我正在进行的项目,我需要模拟某些类进行测试,以测试函数的不同行为。 For testing I use gtest.
对于测试,我使用 gtest。 Because I am working on a game, the speed and efficiency of the code is of the essence.
因为我在做一个游戏,所以代码的速度和效率是至关重要的。 Because of this requirement I do not want to mock my classes by using virtual functions, but I want to mock my classes with templates, so the implementation of the classes will be defined at compile time and I do not lose performance at run time.
由于这个要求,我不想使用虚函数来模拟我的类,但我想用模板模拟我的类,所以类的实现将在编译时定义,我不会在运行时失去性能。 Furthermore, because I want to have the least amount of code bloat in my other header/source files I want to split my files into headers and source files, so that some of the includes can be set in the source file.
此外,因为我希望在我的其他头文件/源文件中拥有最少的代码膨胀量,我想将我的文件拆分为头文件和源文件,以便可以在源文件中设置一些包含。 This approach however comes with a couple of problems.
然而,这种方法有几个问题。
Because the templated functions are defined in a source file, there will need to be an explicit definition of the classes in the source file.因为模板函数是在源文件中定义的,所以需要在源文件中明确定义类。 Otherwise these templated functions will throw an 'undefined external symbol' error at compile time.
否则,这些模板化函数将在编译时抛出“未定义的外部符号”错误。 This would not be a problem if I did not have two different projects, one for the game and one for testing, as I can't make an explicit definition of a mock in the test project.
如果我没有两个不同的项目,一个用于游戏,一个用于测试,这将不是问题,因为我无法在测试项目中明确定义模拟。
I have tried a couple of solutions, but all of them have drawbacks.我尝试了几种解决方案,但它们都有缺点。 I will try to demonstrate what I have done with the following piece of code: (I know and use GMock, but this is an easier example)
我将尝试用以下代码演示我所做的:(我知道并使用 GMock,但这是一个更简单的示例)
//Game project
//Foo.h
<template class Bar>
class Foo
{
public:
Bar bar;
bool ExampleFunction();
}
//Foo.cpp
#include "Foo.h"
<template class Bar>
bool Foo::ExampleFunction()
{
return bar.Func() > 10;
}
//Testing project
//BarMock.h
class BarMock
{
public:
int Func();
int value;
}
//BarMock.cpp
#include "BarMock.h"
Bar::Func()
{
return value;
}
//TestFoo.cpp
#include "Foo.h"
TEST(Tests, TestExample)
{
Foo<BarMock> mocked;
mocked.bar.value = 100;
ASSERT_TRUE(mocked.ExampleFunction());
}
//TestFoo.cpp #include "Foo.h" #include "Foo.cpp" // error prone, but does compile TEST(Tests, TestExample) { Foo<BarMock> mocked; mocked.bar.value = 100; ASSERT_TRUE(mocked.ExampleFunction()); }
//Game project //Foo.h <template class Bar> class Foo { public: Bar bar; bool ExampleFunction() { return bar.Func() > 10; } } //Foo.cpp removed
//BarMock.h class BarMock { public: int Func() override; int value; } //BarMock.cpp #include "BarMock.h" Bar::Func() override { return value; }
Which one of these options is the best?这些选项中哪一个是最好的? Is there any method that I have missed?
有什么我错过的方法吗? I would love to hear someone's opinion about this as I could not find a 'good' solution online.
我很想听听有人对此的看法,因为我在网上找不到“好的”解决方案。
A variation of solution #1 by renaming the files:通过重命名文件的解决方案#1的变体:
#pragma once // or/and header guards
<template class Bar>
class Foo
{
public:
Bar bar;
bool ExampleFunction();
};
#pragma once // or/and header guards
#include "Foo.h"
template <class Bar>
bool Foo<Bar>::ExampleFunction()
{
return bar.Func() > 10;
}
#include "Foo.h"
#include "Foo.inc"
#include "Bar.h"
// explicit instantiation
template <> struct Foo<Bar>;
#include "Foo.h"
#include "Foo.inc"
#include "BarMock.h"
// Testing code...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.