assertEventually

Growing Object-Oriented Software, Guided by Tests (Addison-Wesley Signature Series (Beck))で紹介されていた assertEventually を実装した。これは何かというと「非同期の Unit Test で結果が期待されるものになるまでポーリングする」 assert 。
紹介されていた実装では「ポーリング」を実装した Poller クラスと「期待された状態をチェックする」 Probe インターフェースを定義していてうまく抽象化されている。

利用方法

今回は terminal の出力に特定の文字列が現れるかどうか?をタイムアウト付きでテストした。まず Probe のサブクラスで「期待された状態をチェック」するコードを書く。

class TerminalOutputProbe : public Probe
{
private:
    TestTerminal& terminal_;
    std::string lastContent_;
    std::string contentToMatch_;
public:
    TerminalOutputProbe(TestTerminal& terminal, const std::string& contentToMatch) : 
        terminal_(terminal),
        contentToMatch_(contentToMatch)
    {
    }

    void sample()
    {
        lastContent_ = terminal_.getOutput();
    }
    bool isSatisfied()
    {
        return lastContent_.find(contentToMatch_) != std::string::npos;
    }

    void describeTo(std::string& d)
    {
        d += "<";
        d += contentToMatch_;
        d += ">";
    }

    void describeFailureTo(std::string& d)
    {
        d += "<";
        d += lastContent_;
        d += "> ";
    }
};

あとは以下のように ASSERT_EVENTUALLY に渡すだけ。ASSERT_EVENTUALLY が大文字になっているのは __FILE__, __LINE__ を assertEventually に渡すため。

    TerminalOutputProbe probe(*testTerminal, "HELLO.EX5");
    ASSERT_EVENTUALLY(probe);