作者:佚名
原文链接:http://googletesting.blogspot.tw/2008/10/tott-contain-your-environment.html
许多模块必须访问它们的环境元素,这些元素在测试中可以说的上是十分重量级的。例如,文件系统或网络。为了使测试保持轻巧,我们可以模拟出这些元素。但是,如果没有可用的模拟接口,或者现有的接口会引入外部的依赖呢?在这种情况下,我们可以引入直接与模块关联的(通常为一个公共的内部类)中介接口。我们称这种中介为“Env”(环境);这个名字可以帮助阅读这个类的人员意识到这个接口的目的。
例如,想想有这么一个在存储系统底层级来清理文件系统的类:
//删除从存储系统再不可达的文件 // 元数据. class FileCleaner { public: class Env { public: virtual bool MatchFiles(const char* pattern, vector* filenames) = 0; virtual bool BulkDelete(const vector& filenames) = 0; virtual MetadataReader* NewMetadataReader() = 0; virtual ~Env(); }; // 构造一个文件清理器,使用”env”来获取文件和元数据 FileCleaner(Env* env, QuotaManager* qm); //通过metadata删除不可达的文件 // 返回true或false bool CleanOnce(); };
FileCleaner::Env让我们测试FileCleaner时无需访问真正的文件系统或元数据。它也可以很容易地模拟各种故障,例如,文件系统故障:
class NoFileSystemEnv : public FileCleaner::Env { virtual bool MatchFiles(const char* pattern, vector* filenames) { match_files_called_ = true; return false; } ... }; TEST(FileCleanerTest, FileCleaningFailsWhenFileSystemFails) { NoFileSystemEnv* env = new NoFileSystemEnv(); FileCleaner cleaner(env, new MockQuotaManager()); ASSERT_FALSE(cleaner.CleanOnce()); ASSERT_TRUE(env->match_files_called_); }
一个 Env 对象对于限制访问其它模块或系统是特别有用,例如,当有些模块具有过分宽泛的接口时。还有一个额外的好处是它会减少你对类的依赖。但是,要小心保持“真正的”Env实现简单,免得引入难以找到的bug。你的“真实”的Env实现方法应该只委托给其他完善的、测试过的方法。
一个Env的最重要的好处是:它说明了类如何访问它的环境,并鼓励未来通过扩展和模拟Evn对模块进行修改,以保持测试集的简单。