我正在尝试编写GameBoy模拟器,但我不确定应该如何测试我的CPU_LR39502类。为了避免巨大的if-else-if / switch-case语句,我想出了将操作码仿函数放入map中的想法,它将操作码作为键:
class Functor
{
std::function<void()> m_function;
public:
Functor(std::function<void()>&& function)
{
m_function = std::move(function);
}
void operator()()
{
m_function();
}
};
class BaseOpcodeFunctor : public Functor
{
unsigned char m_opcode;
std::string m_disasmString;
public:
BaseOpcodeFunctor(std::function<void()>&& function,
unsigned char opcode,
std::string&& disasmString)
: Functor(std::move(function)),
m_opcode(opcode),
m_disasmString(std::move(disasmString)) {}
std::string disasm()
{
return m_disasmString;
}
unsigned char getAssignedOpcode()
{
return m_opcode;
}
};
其中的例子:
class CPU_LR35902
{
...
std::map<unsigned char, BaseOpcodeFunctor> m_baseOpcodeMap;
public:
CPU_LR35902()
{
...
initializeBaseOpcodeMap();
}
...
private:
void addFunctorToBaseOpcodeMap(BaseOpcodeFunctor&& functor);
void initializeBaseOpcodeMap()
{
...
addFunctorToBaseOpcodeMap(BaseOpcodeFunctor([this]() {
bitwiseRotationLeft(REGISTER_A);
}, 0x07, "RLCA"));
}
void bitwiseRotationLeft(LR35902_8BIT_REGISTERS reg)
{
resetFlag(FLAG_Z);
resetFlag(FLAG_N);
resetFlag(FLAG_H);
setFlag(FLAG_C, registers_8bit.at(reg) >> 7);
registers_8bit.at(reg) <<= 1;
registers_8bit.at(reg) |= getFlag(FLAG_C);
}
...
};
这让我想到了两个问题。我实际上想在将其添加到m_baseOpcodeMap时立即编写操作码的实现,但为了使其可测试,我将实现编写为成员函数(此处为bitwiseRotationLeft)并且我在lambda中调用它 - 我不确定这是否是正确的做法。
目前,为了测试一些实现,我有类似的东西(使用谷歌测试框架):
#include "cpu_lr35902.h"
#include <gtest/gtest.h>
class CPUTest : public ::testing::Test
{
protected:
CPU_LR35902 cpu_testable;
};
TEST_F(CPUTest, test_bitwiseRotationLeft)
{
cpu_testable.flags = 0;
cpu_testable.clearRegisters();
//0xA5 = 1010 0101, after: 0100 1011 = 0x4B
cpu_testable.registers_8bit.at(CPU_LR35902::REGISTER_A) = 0xA5;
cpu_testable.bitwiseRotationLeft(CPU_LR35902::REGISTER_A);
ASSERT_EQ(1, cpu_testable.getFlag(CPU_LR35902::FLAG_C));
ASSERT_EQ(0x4B, cpu_testable.registers_8bit.at(CPU_LR35902::REGISTER_A));
}
但要访问CPU_LR35902的私有成员,我必须添加
FRIEND_TEST(CPUTest, test_name);
在CPU_LR35902类中的- 之后我可以在TEST_F中访问测试类的私有成员,但是我无法在CPUTest类中访问它们(对于SetUp / TearDown)。考虑到这个事实,我有更多的测试,我将会有很多测试,我认为为每次测试添加FRIEND_TEST会让一切看起来都很糟糕。我已经与C ++联系了一段时间,但我在使用Google Test Framework方面完全没有经验,我的直觉告诉我必须有更好的方法来实现它。任何线索将很高兴地欣赏:)
答案 0 :(得分:3)
How do I test private class members without writing FRIEND_TEST()s?
将测试写为夹具类的成员:
class Foo {
friend class FooTest;
...
};
class FooTest : public ::testing::Test {
protected:
...
void Test1() {...} // This accesses private members of class Foo.
void Test2() {...} // So does this one.
};
TEST_F(FooTest, Test1) {
Test1();
}
TEST_F(FooTest, Test2) {
Test2();
}
这使得每个测试夹具只需要一个类,而不需要在标题(或项目)中包含gtest。
你也可以创建一个普通类,它是主类的朋友,纯粹被测试用来访问私有成员。
class Foo {
friend class FooTesting;
...
};
class FooTesting {
public:
static int read_private_variable1( Foo& );
};
TEST_F(FooTest, Test1) {
Foo bar;
EXPECT_EQ( FooTesting::read_private_variable1( bar ), 5 );
}
答案 1 :(得分:1)
可能不是您要找的答案,但您可以有条件地将cpu参数公开用于测试
class CPU_LR35902
{
...
public:
...
#ifndef TESTING_CPU
private:
#endif
...
};