我正在尝试进行单元测试以测试DoLogin方法:
CLoginActivity::CLoginActivity()
{
m_pTask = new Task();
}
void CLoginActivity::DoLogin()
{
m_pTask.execute();
}
其中Task是我需要模拟的另一个类。
class MockTask : public Task
{
public:
MOCK_METHOD0(Execute, void());
};
要注入MockTask task
对象,我必须改变我的构造:
CLoginActivity::CLoginActivity(Task& task)
{
m_pTask = task;
}
或写一组函数:
CLoginActivity::SetTask(Task& task)
{
m_pTask = task;
}
是否有其他方法可以注入这两种方法?我在单元测试项目中使用gmock。
答案 0 :(得分:2)
通过构造函数注入是最好的 - 保持这种设计。
但对于那些喜欢使简单事物复杂化的人来说,很少有其他方法。
1)制作你的CLoginActivity类模板:
template <class TaskImpl>
class CLoginActivityTemplate
{
CLoginActivityTemplate() { m_pTask = new TaskImpl(); }
};
using CLoginActivity = CLoginActivityTemplate<Task>;
在测试中,测试一下这个实例:
using CLoginActivityTestable = CLoginActivityTemplate<TaskMock>;
然而,它并不总是那么容易 - 因为通常很难访问这个模拟器来设置它。但是您可以定义TestMockWrapper类 确保轻松访问模拟任务:
class TestMockWrapper : public TestMock
{
public:
static TestMock* lastCreated;
TestMockWrapper() { lastCreated = this; }
};
using CLoginActivityTestable = CLoginActivityTemplate<TaskMockWrapper>;
2)将工厂对象注入构造函数:
CLoginActivity::CLoginActivity(ITaskFactory& taskFactory)
{
m_pTask = taskFactory.create();
}
您需要模拟此工厂类以确保mock-factory创建模拟对象。也许它看起来没什么好看的 - 但这只是下一点的介绍。
3)在其他文件中实现特殊工厂功能:
CLoginActivity.cpp
#include "TaskCreate.hpp"
CLoginActivity::CLoginActivity()
{
m_pTask = taskCreate();
}
TaskCreate.cpp
// your "real" function here
ITask* createTask() { return new Task(); }
有了这样的设计 - 只使用项目中的选定文件为您的CLoginActivity创建UT测试 - 简单来说 - 在您的UT项目中用TaskcreateStub.cpp替换TaskCreate.cpp:
TaskCreateStub.cpp应该返回task-mock - 不是真正的任务。您还需要访问此返回的模拟对象 - 因此您可以设置它的期望。
TaskCreateStub.cpp
// your "real" function here
static TaskMock* taskMockForCreateStub = nullptr;
ITask* createTask() { return taskMockForCreateStub ; }
void setTaskMockForCreateTaskStub(TaskMock* taskMock) { taskMockForCreateStub = taskMock; }
我强烈反对您不使用此类链接器级别的模拟。仅用于测试无法重新设计的遗留代码,这可能是使用mock ...
的唯一方法