私は、応答するかもしれない、あるいは応答しないかもしれないハードウェアに依存します。その結果、私はタイムアウトのある関数を書くことがよくあります。システム時間は脆弱な単体テストの既知の原因ですので、制御された安定した時間を注入することはテストのための良い考えのようです。ユニットテストのためにsystem_clockを注入するための機能がstd :: chronoにありますか?
std :: chronoには、それを助ける機能があるのだろうかと思います。私が見る代わりに、システム時間の周りにラッパーを記述し、そのアダプタに依存することです。
ここでは、ラッパーの外観の最小例を示します。
#pragma once
#include <memory>
#include <chrono>
#include <thread>
#include <iostream>
using std::chrono::system_clock;
using std::chrono::milliseconds;
using std::shared_ptr;
using std::make_shared;
class Wrapped_Clock
{
public:
virtual system_clock::time_point Now() { return system_clock::now(); }
virtual void Sleep(milliseconds ms) { std::this_thread::sleep_for(ms); }
};
class Mock_Clock : public Wrapped_Clock
{
private:
system_clock::time_point now;
public:
Mock_Clock() : now(system_clock::now()){}
~Mock_Clock() {}
system_clock::time_point Now() { return now; }
void Sleep(milliseconds ms) { }
};
class CanTimeOut
{
private:
shared_ptr<Wrapped_Clock> sclock;
public:
CanTimeOut(shared_ptr<Wrapped_Clock> sclock = make_shared<Wrapped_Clock>()) : sclock(sclock) {}
~CanTimeOut() {}
milliseconds TimeoutAction(milliseconds maxtime)
{
using std::chrono::duration_cast;
int x = 0;
system_clock::time_point start = sclock->Now();
system_clock::time_point timeout = sclock->Now() + maxtime;
while (timeout > sclock->Now() && x != 2000)
{
sclock->Sleep(milliseconds(1));
++x;
}
milliseconds elapsed = duration_cast<milliseconds>(sclock->Now() - start);
return elapsed;
}
};
#define EXPECT_GE(left, right, test) \
{ if (!(left >= right)) { \
std::cout << #test << " " << "!(" << left << " >= " << right << ")" << std::endl; \
} }
#define EXPECT_EQ(expected, actual, test) \
{ if (!(expected == actual)) { \
std::cout << #test << " " << "!(" << expected << " == " << actual << ")" << std::endl; \
} }
void TestWithSystemClock()
{
CanTimeOut cto;
long long timeout = 1000;
milliseconds actual = cto.TimeoutAction(milliseconds(timeout));
EXPECT_GE(actual.count(), timeout, TestWithSystemClock);
}
void TestWithMockClock()
{
CanTimeOut cto(make_shared<Mock_Clock>());
milliseconds actual = cto.TimeoutAction(milliseconds(1000));
EXPECT_EQ(0, actual.count(), TestWithMockClock);
}
int main()
{
TestWithSystemClock();
TestWithMockClock();
}
どのくらいこれをstd :: chroneの機能で置き換えることができますか?
編集1:
- "あなたは正確に何をテストしています?" 時間に依存するメソッド呼び出しの動作を変更するためのテスト条件として時間を制御しています。このテストでは、時間を嘲笑し、概念を働かせながら行動を制御し、それを理解していることが示されています。最小限の例のポイントは、
std::
施設との違いをより簡単に表示できるように時間を捉えることを理解することです。 - "テストが対比すべきことを言って〜10単語を費やしています。" 1つのテストが常にタイムアウトします。他のテストは時間の経過を示さない。正確で非ゼロの時間経過を制御する第3の試験は含まれていなかった。
- "さらに、睡眠は時計とは関係がありません。クロノの機能ではありません。" タイムアウトする前に1回のテストが一定量以上ループしないようにするために必要でした。これは、時間がかかりタイムアウトになるような動作をシミュレートします。一方、私はショートカットを作成したいので、2回目のテストでは時間を無駄にすることはありません。睡眠を模擬しないこともOKですが、テストには2秒かかります。私は、スリープはクロノ機能ではなく、誤解を招くという点を認識しています。
あなたが正確に何をテストしていますか?条件は私にとってはほとんどわかりにくいです。おそらく、あなたはテストが対比すべきことを言って〜10単語を費やすことができました。また、「スリープ」は時計とは関係がありません。 'クロノ '機能ではない – sehe
ムービングパーツ(タイマーのようなもの)を使用すると、実際にはユニットテストではなくなりました。 – erip
@eripタイマーが偽装された場合、ユニットテストになりますか?その理由を強調しているソースへのリンクを共有できますか? – Johannes