Sono dipendente dall'hardware che potrebbe rispondere o meno. Di conseguenza, finisco spesso per scrivere funzioni con timeout. Il tempo di sistema è una fonte nota per i test di unità fragili, quindi iniettare un tempo controllato e stabile sembra una buona idea per il test.Ci sono strutture in std :: chrono per assistere con l'iniezione system_clock per il test dell'unità
Mi chiedo se ci sono strutture in std :: chrono che aiutano in questo. L'alternativa che vedo è scrivere un wrapper attorno al tempo di sistema e dipendere da quell'adattatore.
Ecco un esempio minimo di come potrebbe apparire un wrapper.
#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();
}
Quanto di questo può essere sostituito con funzionalità da std :: chrone?
Edit 1:
- "Che cosa stai testando?" Sto controllando il tempo come condizione di test per modificare il comportamento delle chiamate di metodo che dipendono dal tempo. Il Test illustra come prendersi gioco del tempo e controllare il comportamento come un concetto funziona e mostra la mia comprensione di esso. Il punto dell'esempio minimo è mostrare la mia comprensione del tempo di derisione per rendere più facile mostrare le differenze alle strutture
std::
. - "spendi ~ 10 parole dicendo che cosa devono essere contrastati i test." L'unico test scade sempre. L'altro test non mostra passaggi di tempo. Un terzo test che controlla un passaggio di tempo esatto e non zero non è stato incluso.
- "Inoltre, il sonno non ha nulla a che fare con l'orologio, non è un crono." Ne avevo bisogno per garantire che l'unico test non effettuasse mai più cicli di una certa quantità prima del timeout, questo simula un'azione che richiede tempo e può scadere. D'altra parte volevo costruire in una scorciatoia così il secondo test non fa perdere tempo ad aspettare. Sarebbe bene non prendere in giro anche Sleep, ma il test richiederebbe 2 secondi. Riconosco il punto che Sleep non è una caratteristica di cronografo e quindi fuorviante.
Che cosa stai testando? Le condizioni sono quasi incomprensibili per me. Forse potresti spendere ~ 10 parole per dire che cosa dovrebbero contraddire i test. Inoltre, 'dormire' non ha niente a che fare con l'orologio. Non è una funzione 'chrono' – sehe
Nota che se usi parti mobili (come un timer), in realtà non è più un test unitario. – erip
@erip sarebbe un test di unità se il timer è deriso? Puoi condividere un link con una fonte che sottolinea perché è così? – Johannes