OO编程实践之“同步文件夹”——实现(1)

标题写的是设计,其实这里应该是写测试。刚才开始很难写出测试来,因为传统编程思维的影响。如果是以前,这段代码也许很快就能写出个能用的版本。但现在我需要提高的我代码质量,不能永远停留在那个脚步。

根据前面的需求,首先想到的是,我如何判断source中的文件比dest中的新。噢,我们只需比较最后的修改时间就行了。

于是我写了关于修改时间的简单测试

    FileModifyTime source(std::time(NULL));
    FileModifyTime dest(std::time(NULL)-1000);
    CPPUNIT_ASSERT(source.isNewerThan(dest));
    CPPUNIT_ASSERT(!source.isNewerThan(source));
    CPPUNIT_ASSERT(!dest.isNewerThan(source));

  接着,我就写实现代码了。

    class FileModifyTime
    {
    public:
        FileModifyTime(time_t modifyTime) : itsModifyTime(modifyTime){}
        bool isNewerThan(const FileModifyTime& fi){ return itsModifyTime > fi.itsModifyTime;}
    private:
        time_t itsModifyTime;
    };

运行测试,通过了。太简单了,离我实际应用太远了。

对于第一次尝试TDD开发,我真不知道如何来写测试。考虑到测试一般而言,是给定一系列输入,然后查看输出是否与期望的相符合。在这个小程序中,我的输入是什么呢?我的输出又是什么呢?于是进入了漫长的思考中...

考虑这个程序的核心作用在source中找出已经改动的文件或者文件夹,那么测试的输入应该是各种文件信息的输入,输出是应该是是否需要更新的bool值,于是测试代码大概是这样:

Folder source("sourceFolder");
Folder dest("destFolder");
SynchronousSystem SS(&source,&dest);

CPPUNIT_ASSERT(SS.isNeedUpdate("File1"));
CPPUNIT_ASSERT(SS.isNeedUpdate("File2") == false);

这一步可能跨度有点大,因为我需要写2个类。

先写个空类能保持编译通过。

class Folder
{
public:
    Folder(const std::string& path){}
};
class Folder;
class SynchronousSystem
{
public:
    SynchronousSystem(Folder* source,Folder* dest){}
    bool isNeedUpdate(const std::string& filename)
    {
        return true;
    }
};

编译通过,但测试不通过。引文这里的我直接返回了true。为了使其通过测试,我修改了isNeedUpdate函数

    bool isNeedUpdate(const std::string& filename)
    {
        if(filename == "File1")
            return true;
        else
            return false;
    }

测试通过了,但isNeedUpdate的作用应该是判断文件修改时间,这个需要从source和dest中读取文件信息,于是继续编写测试代码:

    Folder source("sourceFolder");
    Folder dest("destFolder");

    CPPUNIT_ASSERT(source.getFileModifyTime("File1").isNewerThan(dest.getFileModifyTime("File1"));
    CPPUNIT_ASSERT(source.getFileModifyTime("File2").isNewerThan(dest.getFileModifyTime("File2") == false);

于是在Folder中需要增加成员函数getFileModifyTime

    FileModifyTime getFileModifyTime(const std::string& filename)
    {
        return FileModifyTime(std::time(NULL));
    }

为了使测试通过,我们需要在Folder中做一些工作。

class Folder
{
public:
    Folder(const std::string& path):itsPath(path){}
    FileModifyTime getFileModifyTime(const std::string& filename)
    {
        if (filename == "File1" && itsPath == "destFolder")
            return FileModifyTime(std::time(NULL)-1000);
        if (filename == "File2" && itsPath == "sourceFolder")
            return FileModifyTime(std::time(NULL)-1000);
        return FileModifyTime(std::time(NULL));
    }
private:
    std::string itsPath;
};

这样所有测试都通过了,再回过头来看SynchronousSystem,它的isNeedUpdate函数应该调用Folder看查询文件的修改时间,类SynchronousSystem修改为

class SynchronousSystem
{
public:
    SynchronousSystem(Folder* source,Folder* dest):itsSourceFolder(source),itsDestFolder(dest){}
    bool isNeedUpdate(const std::string& filename)
    {
        return itsSourceFolder->getFileModifyTime(filename).isNewerThan(itsDestFolder->getFileModifyTime(filename));
    }
private:
    Folder* itsSourceFolder;
    Folder* itsDestFolder;
};

一切很好,所有测试都通过了。

这样看来,一个功能1差不多完成了,考虑功能2的情况,如果dest中的文件不存在,那么isNeedUpdate中应该返回true。测试代码:

    Folder source("sourceFolder");
    Folder dest("destFolder");
    SynchronousSystem SS(&source,&dest);
    CPPUNIT_ASSERT(SS.isNeedUpdate("FileNotExist"));

测试不通过,我们更新isNeedUpdate函数

    bool isNeedUpdate(const std::string& filename)
    {
        if(!itsDestFolder->isExist(filename))
            return true;
        return itsSourceFolder->getFileModifyTime(filename).isNewerThan(itsDestFolder->getFileModifyTime(filename));
    }

类Folder中增加

    bool isExist(const std::string& filename)
    {
        if(filename == "FileNotExist")
            return false;
        else
            return true;
    }

测试通过了。

原文地址:https://www.cnblogs.com/zhangyonghugo/p/2568608.html