OOプログラミング実践の「同期フォルダ」――実現(1)

11761 ワード

タイトルはデザインですが、実はここはテストを書くべきです.さっきからテストを書くのは難しいです.伝統的なプログラミング思考の影響です.以前なら、このコードはすぐに使えるバージョンを書くことができたかもしれません.しかし、今私はコードの品質を高める必要があります.永遠にその足どりにとどまることはできません.
前のニーズに基づいて、まず考えたのは、destの新しいファイルよりもsourceのファイルをどのように判断するかです.ああ、最後の修正時間を比較するだけでいいです.
そこで修正時間について簡単なテストを書きました
    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つの機能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;

    }

テストに合格した.