我有一个包含规则的二进制文件。我将这些规则解析为对象并对它们扫描文件。我现在的对象模型,像这样:如何让这些类更加单元测试友好?
struct TypeARule
{
// rule internals
};
struct TypeBRule
{
// rule internals
};
struct TypeCRule
{
// rule internals
};
struct RuleDatabase
{
vector<TypeARule> TypeA;
vector<TypeBRule> TypeB;
vector<TypeCRule> TypeC;
};
class RuleParser
{
public:
bool ParseFile(const string& path, RuleDatabase& database)
{
// open file, read records from file, generate objects from records, add objects to database
}
private:
// misc helper methods
};
class RuleScanner
{
public:
bool ScanFile(const string& path, const RuleDatabase& database)
{
if(ScanTypeA(path, database))
{
return true;
}
if(ScanTypeB(path, database))
{
return true;
}
if(ScanTypeC(path, database))
{
return true;
}
return false;
}
private:
bool ScanTypeA(const string& path, const RuleDatabase& database)
{
for(const auto& rule : database.TypeA)
{
if (rule matches path))
{
return true;
}
}
return false;
}
bool ScanTypeB(const string& path, const RuleDatabase& database)
{
for(const auto& rule : database.TypeB)
{
if (rule matches path))
{
return true;
}
}
return false;
}
bool ScanTypeC(const string& path, const RuleDatabase& database)
{
for(const auto& rule : database.TypeA)
{
if (rule matches path))
{
return true;
}
}
return false;
}
};
class Client
{
public:
bool Initialize(const string& path)
{
RuleParser parser;
return parser.ParseFile(path, m_database);
}
bool ScanFile(const string& path)
{
RuleScanner scanner;
return scanner.ScanFile(path, m_database);
}
void Cleanup()
{
// cleanup m_database
}
private:
RuleDatabase m_database;
};
我明白依赖注入将与测试Client
类(通过传递引用嘲笑RuleParser
和RuleScanner
对象,它的构造函数)的帮助。但是,我需要做些什么来单元测试RuleParser
和RuleScanner
类?因为RuleDatabase
是用于存储其他对象的哑对象,所以在当前模型中依赖注入不起作用。我最初的想法是修改RuleDatabase
以隐藏其数据成员并提供公开的方法来对其进行操作,例如ParseTypeA()
,ParseTypeB()
,ScanTypeA()
,ScanTypeB()
。但是,我认为这似乎是模糊了班级职责之间的界限(例如,RuleParser
应该执行所有解析工作,而RuleScanner
应该执行所有扫描工作)。有没有更干净的方法来做到这一点?
目前,你可以单独测试'Parser','Scanner'没有'Parser'(你必须自己创建'RuleDatabase')。 “客户”大多只是转发它的任务,所以测试它主要是集成测试。 – Jarod42
这真的取决于你想测试什么。如果它只是一个简单的测试,比如'TestScanFileReturnsTrueWhenDatabaseContainsX',那么你可以很容易地预先填充一个'RuleDatabase'对象,并将它传递给你的'ScanFile'方法。当测试应该模拟对象时,并非所有传递给方法的东西 –
*“如何让这些类更易于使用单元测试?” - 单元测试不应损害类架构! –