Mockable clock meeting std::chrono TrivialClock requirement and interface











up vote
3
down vote

favorite












I'm using the time for e.g. ping and timeout calculation as well as animations in a game. So my (big) codebase uses std::chrono::steady_clock::now() in many places. For testing I'd like to test those without having to resort to sleep and friends (timeout of >=5mins will be hard to test this way...)



For this I created a custom Clock class that uses a singleton-like instance which can be changed to provide a custom clock. A default of steady_clock is used for production code. This Clock can be used as a drop-in replacement of std::chrono::steady_clock and can be mocked in test code.



I'd like a review with suggestions how to improve this or if it has any flaws. Pointers to similar/better implementations are also welcome. I'm mostly concerned about the multiple indirections (and related performance penalties) this causes: Lookup of a "constructed" flag, the impl and the vtable (3 pointers) although I only have 1 function. See godbold



#include <chrono>
#include <memory>

struct BaseClock
{
using Clock = std::chrono::steady_clock;
using time_point = Clock::time_point;
virtual ~BaseClock() = default;
virtual time_point now(){ return std::chrono::steady_clock::now(); }
};

class Clock
{
static std::unique_ptr<BaseClock>& inst(){
static std::unique_ptr<BaseClock> clock(new BaseClock);
return clock;
}
public:
using rep = BaseClock::Clock::rep;
using duration = BaseClock::Clock::duration;
using time_point = std::chrono::time_point<Clock>;

static time_point now(){ return time_point(inst()->now().time_since_epoch()); }
static void set(std::unique_ptr<BaseClock> clock){inst() = std::move(clock);}
};

int main()
{
return Clock::now().time_since_epoch().count();
}


Example usage in test code:



struct MockClock: public BaseClock{
static time_point current;
time_point now() override { return current; }
};

void test_method(){
Clock::set(new MockClock);
MockClock::current = MockClock::time_point(100);
testClass.methodUsingClock();
MockClock::current += std::chrono::seconds(10);
REQUIRE(testClass.checkTimeout());
}









share|improve this question
























  • What's the point of BaseClock ? What's advantage against using directly std::chrono ? Avoid naked new, use std::make_unique instead.
    – Calak
    15 hours ago










  • @Calak: IIUC the point of BaseClock is to provide a baseline clock interface without direct dependencies. A user expecting a const BaseClock& or similiar can now write code independent of the underlying clock type. This allows for switching the underlying clock on a higher level without affecting the dependent code (kind of "dependency injection for clocks"). As a side effect, this allows for easier test setups (especially for weird corner cases). // I'm not a fan of the singleton in Clock, though.
    – hoffmale
    14 hours ago










  • I once did a mockable clock, with support for mutex timeouts as well. I don't have time to review this right now, as I'm about to head out for a bit, but I hope to look at this when I return on Tuesday. Reply to this comment to remind me if I've not responded by Wednesday 28th November.
    – Toby Speight
    13 hours ago










  • @Calak In test code you need to mock the time, that's the whole purpose that I stated in the intro. Hence you need some injection point which the virtual BaseClock::now() provides while defaulting to std::chrono. I added a usage example to make this clearer.
    – Flamefire
    12 hours ago










  • @hoffmale You are correct, although the code does not get BaseClock& but simply uses Clock as a drop-in replacement for std::chrono::*clock (I edited the question to highlight this) So yes this is exactly dependency injection but without passing it as (template or regular) parameters which would require massive changes to the codebase. As clocks are static classes a singleton is required, I don't see a way avoiding this.
    – Flamefire
    12 hours ago

















up vote
3
down vote

favorite












I'm using the time for e.g. ping and timeout calculation as well as animations in a game. So my (big) codebase uses std::chrono::steady_clock::now() in many places. For testing I'd like to test those without having to resort to sleep and friends (timeout of >=5mins will be hard to test this way...)



For this I created a custom Clock class that uses a singleton-like instance which can be changed to provide a custom clock. A default of steady_clock is used for production code. This Clock can be used as a drop-in replacement of std::chrono::steady_clock and can be mocked in test code.



I'd like a review with suggestions how to improve this or if it has any flaws. Pointers to similar/better implementations are also welcome. I'm mostly concerned about the multiple indirections (and related performance penalties) this causes: Lookup of a "constructed" flag, the impl and the vtable (3 pointers) although I only have 1 function. See godbold



#include <chrono>
#include <memory>

struct BaseClock
{
using Clock = std::chrono::steady_clock;
using time_point = Clock::time_point;
virtual ~BaseClock() = default;
virtual time_point now(){ return std::chrono::steady_clock::now(); }
};

class Clock
{
static std::unique_ptr<BaseClock>& inst(){
static std::unique_ptr<BaseClock> clock(new BaseClock);
return clock;
}
public:
using rep = BaseClock::Clock::rep;
using duration = BaseClock::Clock::duration;
using time_point = std::chrono::time_point<Clock>;

static time_point now(){ return time_point(inst()->now().time_since_epoch()); }
static void set(std::unique_ptr<BaseClock> clock){inst() = std::move(clock);}
};

int main()
{
return Clock::now().time_since_epoch().count();
}


Example usage in test code:



struct MockClock: public BaseClock{
static time_point current;
time_point now() override { return current; }
};

void test_method(){
Clock::set(new MockClock);
MockClock::current = MockClock::time_point(100);
testClass.methodUsingClock();
MockClock::current += std::chrono::seconds(10);
REQUIRE(testClass.checkTimeout());
}









share|improve this question
























  • What's the point of BaseClock ? What's advantage against using directly std::chrono ? Avoid naked new, use std::make_unique instead.
    – Calak
    15 hours ago










  • @Calak: IIUC the point of BaseClock is to provide a baseline clock interface without direct dependencies. A user expecting a const BaseClock& or similiar can now write code independent of the underlying clock type. This allows for switching the underlying clock on a higher level without affecting the dependent code (kind of "dependency injection for clocks"). As a side effect, this allows for easier test setups (especially for weird corner cases). // I'm not a fan of the singleton in Clock, though.
    – hoffmale
    14 hours ago










  • I once did a mockable clock, with support for mutex timeouts as well. I don't have time to review this right now, as I'm about to head out for a bit, but I hope to look at this when I return on Tuesday. Reply to this comment to remind me if I've not responded by Wednesday 28th November.
    – Toby Speight
    13 hours ago










  • @Calak In test code you need to mock the time, that's the whole purpose that I stated in the intro. Hence you need some injection point which the virtual BaseClock::now() provides while defaulting to std::chrono. I added a usage example to make this clearer.
    – Flamefire
    12 hours ago










  • @hoffmale You are correct, although the code does not get BaseClock& but simply uses Clock as a drop-in replacement for std::chrono::*clock (I edited the question to highlight this) So yes this is exactly dependency injection but without passing it as (template or regular) parameters which would require massive changes to the codebase. As clocks are static classes a singleton is required, I don't see a way avoiding this.
    – Flamefire
    12 hours ago















up vote
3
down vote

favorite









up vote
3
down vote

favorite











I'm using the time for e.g. ping and timeout calculation as well as animations in a game. So my (big) codebase uses std::chrono::steady_clock::now() in many places. For testing I'd like to test those without having to resort to sleep and friends (timeout of >=5mins will be hard to test this way...)



For this I created a custom Clock class that uses a singleton-like instance which can be changed to provide a custom clock. A default of steady_clock is used for production code. This Clock can be used as a drop-in replacement of std::chrono::steady_clock and can be mocked in test code.



I'd like a review with suggestions how to improve this or if it has any flaws. Pointers to similar/better implementations are also welcome. I'm mostly concerned about the multiple indirections (and related performance penalties) this causes: Lookup of a "constructed" flag, the impl and the vtable (3 pointers) although I only have 1 function. See godbold



#include <chrono>
#include <memory>

struct BaseClock
{
using Clock = std::chrono::steady_clock;
using time_point = Clock::time_point;
virtual ~BaseClock() = default;
virtual time_point now(){ return std::chrono::steady_clock::now(); }
};

class Clock
{
static std::unique_ptr<BaseClock>& inst(){
static std::unique_ptr<BaseClock> clock(new BaseClock);
return clock;
}
public:
using rep = BaseClock::Clock::rep;
using duration = BaseClock::Clock::duration;
using time_point = std::chrono::time_point<Clock>;

static time_point now(){ return time_point(inst()->now().time_since_epoch()); }
static void set(std::unique_ptr<BaseClock> clock){inst() = std::move(clock);}
};

int main()
{
return Clock::now().time_since_epoch().count();
}


Example usage in test code:



struct MockClock: public BaseClock{
static time_point current;
time_point now() override { return current; }
};

void test_method(){
Clock::set(new MockClock);
MockClock::current = MockClock::time_point(100);
testClass.methodUsingClock();
MockClock::current += std::chrono::seconds(10);
REQUIRE(testClass.checkTimeout());
}









share|improve this question















I'm using the time for e.g. ping and timeout calculation as well as animations in a game. So my (big) codebase uses std::chrono::steady_clock::now() in many places. For testing I'd like to test those without having to resort to sleep and friends (timeout of >=5mins will be hard to test this way...)



For this I created a custom Clock class that uses a singleton-like instance which can be changed to provide a custom clock. A default of steady_clock is used for production code. This Clock can be used as a drop-in replacement of std::chrono::steady_clock and can be mocked in test code.



I'd like a review with suggestions how to improve this or if it has any flaws. Pointers to similar/better implementations are also welcome. I'm mostly concerned about the multiple indirections (and related performance penalties) this causes: Lookup of a "constructed" flag, the impl and the vtable (3 pointers) although I only have 1 function. See godbold



#include <chrono>
#include <memory>

struct BaseClock
{
using Clock = std::chrono::steady_clock;
using time_point = Clock::time_point;
virtual ~BaseClock() = default;
virtual time_point now(){ return std::chrono::steady_clock::now(); }
};

class Clock
{
static std::unique_ptr<BaseClock>& inst(){
static std::unique_ptr<BaseClock> clock(new BaseClock);
return clock;
}
public:
using rep = BaseClock::Clock::rep;
using duration = BaseClock::Clock::duration;
using time_point = std::chrono::time_point<Clock>;

static time_point now(){ return time_point(inst()->now().time_since_epoch()); }
static void set(std::unique_ptr<BaseClock> clock){inst() = std::move(clock);}
};

int main()
{
return Clock::now().time_since_epoch().count();
}


Example usage in test code:



struct MockClock: public BaseClock{
static time_point current;
time_point now() override { return current; }
};

void test_method(){
Clock::set(new MockClock);
MockClock::current = MockClock::time_point(100);
testClass.methodUsingClock();
MockClock::current += std::chrono::seconds(10);
REQUIRE(testClass.checkTimeout());
}






c++ c++11 mocks






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited 12 hours ago

























asked 15 hours ago









Flamefire

1514




1514












  • What's the point of BaseClock ? What's advantage against using directly std::chrono ? Avoid naked new, use std::make_unique instead.
    – Calak
    15 hours ago










  • @Calak: IIUC the point of BaseClock is to provide a baseline clock interface without direct dependencies. A user expecting a const BaseClock& or similiar can now write code independent of the underlying clock type. This allows for switching the underlying clock on a higher level without affecting the dependent code (kind of "dependency injection for clocks"). As a side effect, this allows for easier test setups (especially for weird corner cases). // I'm not a fan of the singleton in Clock, though.
    – hoffmale
    14 hours ago










  • I once did a mockable clock, with support for mutex timeouts as well. I don't have time to review this right now, as I'm about to head out for a bit, but I hope to look at this when I return on Tuesday. Reply to this comment to remind me if I've not responded by Wednesday 28th November.
    – Toby Speight
    13 hours ago










  • @Calak In test code you need to mock the time, that's the whole purpose that I stated in the intro. Hence you need some injection point which the virtual BaseClock::now() provides while defaulting to std::chrono. I added a usage example to make this clearer.
    – Flamefire
    12 hours ago










  • @hoffmale You are correct, although the code does not get BaseClock& but simply uses Clock as a drop-in replacement for std::chrono::*clock (I edited the question to highlight this) So yes this is exactly dependency injection but without passing it as (template or regular) parameters which would require massive changes to the codebase. As clocks are static classes a singleton is required, I don't see a way avoiding this.
    – Flamefire
    12 hours ago




















  • What's the point of BaseClock ? What's advantage against using directly std::chrono ? Avoid naked new, use std::make_unique instead.
    – Calak
    15 hours ago










  • @Calak: IIUC the point of BaseClock is to provide a baseline clock interface without direct dependencies. A user expecting a const BaseClock& or similiar can now write code independent of the underlying clock type. This allows for switching the underlying clock on a higher level without affecting the dependent code (kind of "dependency injection for clocks"). As a side effect, this allows for easier test setups (especially for weird corner cases). // I'm not a fan of the singleton in Clock, though.
    – hoffmale
    14 hours ago










  • I once did a mockable clock, with support for mutex timeouts as well. I don't have time to review this right now, as I'm about to head out for a bit, but I hope to look at this when I return on Tuesday. Reply to this comment to remind me if I've not responded by Wednesday 28th November.
    – Toby Speight
    13 hours ago










  • @Calak In test code you need to mock the time, that's the whole purpose that I stated in the intro. Hence you need some injection point which the virtual BaseClock::now() provides while defaulting to std::chrono. I added a usage example to make this clearer.
    – Flamefire
    12 hours ago










  • @hoffmale You are correct, although the code does not get BaseClock& but simply uses Clock as a drop-in replacement for std::chrono::*clock (I edited the question to highlight this) So yes this is exactly dependency injection but without passing it as (template or regular) parameters which would require massive changes to the codebase. As clocks are static classes a singleton is required, I don't see a way avoiding this.
    – Flamefire
    12 hours ago


















What's the point of BaseClock ? What's advantage against using directly std::chrono ? Avoid naked new, use std::make_unique instead.
– Calak
15 hours ago




What's the point of BaseClock ? What's advantage against using directly std::chrono ? Avoid naked new, use std::make_unique instead.
– Calak
15 hours ago












@Calak: IIUC the point of BaseClock is to provide a baseline clock interface without direct dependencies. A user expecting a const BaseClock& or similiar can now write code independent of the underlying clock type. This allows for switching the underlying clock on a higher level without affecting the dependent code (kind of "dependency injection for clocks"). As a side effect, this allows for easier test setups (especially for weird corner cases). // I'm not a fan of the singleton in Clock, though.
– hoffmale
14 hours ago




@Calak: IIUC the point of BaseClock is to provide a baseline clock interface without direct dependencies. A user expecting a const BaseClock& or similiar can now write code independent of the underlying clock type. This allows for switching the underlying clock on a higher level without affecting the dependent code (kind of "dependency injection for clocks"). As a side effect, this allows for easier test setups (especially for weird corner cases). // I'm not a fan of the singleton in Clock, though.
– hoffmale
14 hours ago












I once did a mockable clock, with support for mutex timeouts as well. I don't have time to review this right now, as I'm about to head out for a bit, but I hope to look at this when I return on Tuesday. Reply to this comment to remind me if I've not responded by Wednesday 28th November.
– Toby Speight
13 hours ago




I once did a mockable clock, with support for mutex timeouts as well. I don't have time to review this right now, as I'm about to head out for a bit, but I hope to look at this when I return on Tuesday. Reply to this comment to remind me if I've not responded by Wednesday 28th November.
– Toby Speight
13 hours ago












@Calak In test code you need to mock the time, that's the whole purpose that I stated in the intro. Hence you need some injection point which the virtual BaseClock::now() provides while defaulting to std::chrono. I added a usage example to make this clearer.
– Flamefire
12 hours ago




@Calak In test code you need to mock the time, that's the whole purpose that I stated in the intro. Hence you need some injection point which the virtual BaseClock::now() provides while defaulting to std::chrono. I added a usage example to make this clearer.
– Flamefire
12 hours ago












@hoffmale You are correct, although the code does not get BaseClock& but simply uses Clock as a drop-in replacement for std::chrono::*clock (I edited the question to highlight this) So yes this is exactly dependency injection but without passing it as (template or regular) parameters which would require massive changes to the codebase. As clocks are static classes a singleton is required, I don't see a way avoiding this.
– Flamefire
12 hours ago






@hoffmale You are correct, although the code does not get BaseClock& but simply uses Clock as a drop-in replacement for std::chrono::*clock (I edited the question to highlight this) So yes this is exactly dependency injection but without passing it as (template or regular) parameters which would require massive changes to the codebase. As clocks are static classes a singleton is required, I don't see a way avoiding this.
– Flamefire
12 hours ago












1 Answer
1






active

oldest

votes

















up vote
2
down vote













While I think the underlying idea is quite nice, the actual implementation and design has some issues.



Wrong Abstraction Level



Let's start with the less obvious one: How would you actually use Clock or BaseClock with std::chrono::high_resolution_clock or std::chrono::system_clock?



The simplest approach would be something akin to this:



struct HighResClock : BaseClock {
time_point now() override { return std::chrono::high_resolution_clock::now(); }
};


It seems so clean, so simple, and so easy. Except that it doesn't compile! That's because std::chrono::high_resolution_clock::time_point is not the same as BaseClock::time_point (and cannot easily be converted, if at all possible).



But: Do we actually need time_points in the public interface?



The only reason to expose time_point values is to extract time differences between them. But that only matters if arbitrary time_points are to be compared.




Technically, the time_point could be stored in some form. However, for many clocks, like std::chrono::steady_clock or std::chrono::high_resolution_clock, the epoch from when the clock are measuring their time offset can change between different executions of the same program (e.g. because the computer got rebooted).



This makes storing time_points, especially those not obtained from std::chrono::system_clock, rather useless. In that case, you'll likely need a calendar library (or similar) to get points of time in a storable format.




But in most cases, a simple Timer abstraction can fulfill all clock needs (comparing some time_points with some relation). A simple Timer interface could look like this:



struct timer {
// choose an appropriate duration type
using duration = std::chrono::duration<double>;

virtual ~timer() = default;

virtual void start() = 0;
virtual duration stop() = 0;
virtual duration tick() = 0; // to obtain multiple measurements from the same baseline
};

class steady_timer : public timer {
using clock = std::chrono::steady_clock;
using time_point = clock::time_point;

time_point start_time;
bool running;

public:
steady_timer() = default;

void start() override
{
start_time = clock::now();
running = true;
}

duration tick() override
{
return duration(clock::now() - start_time);
}

duration stop() override
{
auto elapsed = tick();
running = false;
return elapsed;
}
};


Now the only exposed part of the interface is the duration. And it is easily extensible to other time sources (e.g. Win32 QueryPerformanceCounter) or mockable.



Singleton



I really don't like the Clock singleton. Yes, it is easy to just ask a global clock. Yes, it is also easy to screw all code depending on this clock by changing the underlying instance.



For example, a test setting Clock to a mock but not restoring the original clock breaks all other tests that assume the default clock implementation - making test failure dependent on test execution order.



Instead, take a reference or pointer to a timer as parameter. This allows you to pass in a clock where needed, without changing (or corrupting) everyone elses timer.



Rewriting your test case:



class mock_timer : public timer {
std::vector<duration> measurements;
int counter = 0;

public:
mock_timer(std::initializer_list<duration> il) : measurements(il) {}

void start() override {}

duration tick() override
{
if(counter < measurements.size()) return measurements[counter++];
return measurements.back();
}

duration stop() override
{
return measurements.back(); // just example
}
};

void test_method(){
using namespace std::literals::chrono_literals;
mock_timer my_timer{ 10s };

testClass.methodUsingClock(my_timer);

// or, more likely:
testclass inst{my_timer};
inst.methodUsingClock();

REQUIRE(testClass.checkTimeout());
}





share|improve this answer





















  • I understand your arguments But I see problems with that: Time is something global, so it makes sense for it being a singleton/global. Passing it to every class would require huge refactoring and passing things down in aggregates etc. which shows another problem: Your timer class cannot be reused! So e.g. a class that needs 2 timers cannot reuse the timer as it would restart. BUT: What if I use my design but change BaseClass::now to return a duration? Then the underlying clock does not matter as long is it returns "time since epoch" and is not changed while a Clock::time_point is held.
    – Flamefire
    10 hours ago










  • @Flamefire: I'm not sure if I am getting your whole argument. I don't think time is something global. Instead, everything has its own perspective on time. For example, a game might be using one clock for rendering and a different clock for logic updates. Why? Because if gameplay is paused (e.g. when entering a menu), the graphics should still continue to be rendered because otherwise the screen would freeze. // RE "time since epoch": When is epoch? What if the epoch changes because the clock is changed? Having mutable global state is just waiting for accidents to happen.
    – hoffmale
    8 hours ago











Your Answer





StackExchange.ifUsing("editor", function () {
return StackExchange.using("mathjaxEditing", function () {
StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
});
});
}, "mathjax-editing");

StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");

StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "196"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});

function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});


}
});














 

draft saved


draft discarded


















StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f208273%2fmockable-clock-meeting-stdchrono-trivialclock-requirement-and-interface%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown

























1 Answer
1






active

oldest

votes








1 Answer
1






active

oldest

votes









active

oldest

votes






active

oldest

votes








up vote
2
down vote













While I think the underlying idea is quite nice, the actual implementation and design has some issues.



Wrong Abstraction Level



Let's start with the less obvious one: How would you actually use Clock or BaseClock with std::chrono::high_resolution_clock or std::chrono::system_clock?



The simplest approach would be something akin to this:



struct HighResClock : BaseClock {
time_point now() override { return std::chrono::high_resolution_clock::now(); }
};


It seems so clean, so simple, and so easy. Except that it doesn't compile! That's because std::chrono::high_resolution_clock::time_point is not the same as BaseClock::time_point (and cannot easily be converted, if at all possible).



But: Do we actually need time_points in the public interface?



The only reason to expose time_point values is to extract time differences between them. But that only matters if arbitrary time_points are to be compared.




Technically, the time_point could be stored in some form. However, for many clocks, like std::chrono::steady_clock or std::chrono::high_resolution_clock, the epoch from when the clock are measuring their time offset can change between different executions of the same program (e.g. because the computer got rebooted).



This makes storing time_points, especially those not obtained from std::chrono::system_clock, rather useless. In that case, you'll likely need a calendar library (or similar) to get points of time in a storable format.




But in most cases, a simple Timer abstraction can fulfill all clock needs (comparing some time_points with some relation). A simple Timer interface could look like this:



struct timer {
// choose an appropriate duration type
using duration = std::chrono::duration<double>;

virtual ~timer() = default;

virtual void start() = 0;
virtual duration stop() = 0;
virtual duration tick() = 0; // to obtain multiple measurements from the same baseline
};

class steady_timer : public timer {
using clock = std::chrono::steady_clock;
using time_point = clock::time_point;

time_point start_time;
bool running;

public:
steady_timer() = default;

void start() override
{
start_time = clock::now();
running = true;
}

duration tick() override
{
return duration(clock::now() - start_time);
}

duration stop() override
{
auto elapsed = tick();
running = false;
return elapsed;
}
};


Now the only exposed part of the interface is the duration. And it is easily extensible to other time sources (e.g. Win32 QueryPerformanceCounter) or mockable.



Singleton



I really don't like the Clock singleton. Yes, it is easy to just ask a global clock. Yes, it is also easy to screw all code depending on this clock by changing the underlying instance.



For example, a test setting Clock to a mock but not restoring the original clock breaks all other tests that assume the default clock implementation - making test failure dependent on test execution order.



Instead, take a reference or pointer to a timer as parameter. This allows you to pass in a clock where needed, without changing (or corrupting) everyone elses timer.



Rewriting your test case:



class mock_timer : public timer {
std::vector<duration> measurements;
int counter = 0;

public:
mock_timer(std::initializer_list<duration> il) : measurements(il) {}

void start() override {}

duration tick() override
{
if(counter < measurements.size()) return measurements[counter++];
return measurements.back();
}

duration stop() override
{
return measurements.back(); // just example
}
};

void test_method(){
using namespace std::literals::chrono_literals;
mock_timer my_timer{ 10s };

testClass.methodUsingClock(my_timer);

// or, more likely:
testclass inst{my_timer};
inst.methodUsingClock();

REQUIRE(testClass.checkTimeout());
}





share|improve this answer





















  • I understand your arguments But I see problems with that: Time is something global, so it makes sense for it being a singleton/global. Passing it to every class would require huge refactoring and passing things down in aggregates etc. which shows another problem: Your timer class cannot be reused! So e.g. a class that needs 2 timers cannot reuse the timer as it would restart. BUT: What if I use my design but change BaseClass::now to return a duration? Then the underlying clock does not matter as long is it returns "time since epoch" and is not changed while a Clock::time_point is held.
    – Flamefire
    10 hours ago










  • @Flamefire: I'm not sure if I am getting your whole argument. I don't think time is something global. Instead, everything has its own perspective on time. For example, a game might be using one clock for rendering and a different clock for logic updates. Why? Because if gameplay is paused (e.g. when entering a menu), the graphics should still continue to be rendered because otherwise the screen would freeze. // RE "time since epoch": When is epoch? What if the epoch changes because the clock is changed? Having mutable global state is just waiting for accidents to happen.
    – hoffmale
    8 hours ago















up vote
2
down vote













While I think the underlying idea is quite nice, the actual implementation and design has some issues.



Wrong Abstraction Level



Let's start with the less obvious one: How would you actually use Clock or BaseClock with std::chrono::high_resolution_clock or std::chrono::system_clock?



The simplest approach would be something akin to this:



struct HighResClock : BaseClock {
time_point now() override { return std::chrono::high_resolution_clock::now(); }
};


It seems so clean, so simple, and so easy. Except that it doesn't compile! That's because std::chrono::high_resolution_clock::time_point is not the same as BaseClock::time_point (and cannot easily be converted, if at all possible).



But: Do we actually need time_points in the public interface?



The only reason to expose time_point values is to extract time differences between them. But that only matters if arbitrary time_points are to be compared.




Technically, the time_point could be stored in some form. However, for many clocks, like std::chrono::steady_clock or std::chrono::high_resolution_clock, the epoch from when the clock are measuring their time offset can change between different executions of the same program (e.g. because the computer got rebooted).



This makes storing time_points, especially those not obtained from std::chrono::system_clock, rather useless. In that case, you'll likely need a calendar library (or similar) to get points of time in a storable format.




But in most cases, a simple Timer abstraction can fulfill all clock needs (comparing some time_points with some relation). A simple Timer interface could look like this:



struct timer {
// choose an appropriate duration type
using duration = std::chrono::duration<double>;

virtual ~timer() = default;

virtual void start() = 0;
virtual duration stop() = 0;
virtual duration tick() = 0; // to obtain multiple measurements from the same baseline
};

class steady_timer : public timer {
using clock = std::chrono::steady_clock;
using time_point = clock::time_point;

time_point start_time;
bool running;

public:
steady_timer() = default;

void start() override
{
start_time = clock::now();
running = true;
}

duration tick() override
{
return duration(clock::now() - start_time);
}

duration stop() override
{
auto elapsed = tick();
running = false;
return elapsed;
}
};


Now the only exposed part of the interface is the duration. And it is easily extensible to other time sources (e.g. Win32 QueryPerformanceCounter) or mockable.



Singleton



I really don't like the Clock singleton. Yes, it is easy to just ask a global clock. Yes, it is also easy to screw all code depending on this clock by changing the underlying instance.



For example, a test setting Clock to a mock but not restoring the original clock breaks all other tests that assume the default clock implementation - making test failure dependent on test execution order.



Instead, take a reference or pointer to a timer as parameter. This allows you to pass in a clock where needed, without changing (or corrupting) everyone elses timer.



Rewriting your test case:



class mock_timer : public timer {
std::vector<duration> measurements;
int counter = 0;

public:
mock_timer(std::initializer_list<duration> il) : measurements(il) {}

void start() override {}

duration tick() override
{
if(counter < measurements.size()) return measurements[counter++];
return measurements.back();
}

duration stop() override
{
return measurements.back(); // just example
}
};

void test_method(){
using namespace std::literals::chrono_literals;
mock_timer my_timer{ 10s };

testClass.methodUsingClock(my_timer);

// or, more likely:
testclass inst{my_timer};
inst.methodUsingClock();

REQUIRE(testClass.checkTimeout());
}





share|improve this answer





















  • I understand your arguments But I see problems with that: Time is something global, so it makes sense for it being a singleton/global. Passing it to every class would require huge refactoring and passing things down in aggregates etc. which shows another problem: Your timer class cannot be reused! So e.g. a class that needs 2 timers cannot reuse the timer as it would restart. BUT: What if I use my design but change BaseClass::now to return a duration? Then the underlying clock does not matter as long is it returns "time since epoch" and is not changed while a Clock::time_point is held.
    – Flamefire
    10 hours ago










  • @Flamefire: I'm not sure if I am getting your whole argument. I don't think time is something global. Instead, everything has its own perspective on time. For example, a game might be using one clock for rendering and a different clock for logic updates. Why? Because if gameplay is paused (e.g. when entering a menu), the graphics should still continue to be rendered because otherwise the screen would freeze. // RE "time since epoch": When is epoch? What if the epoch changes because the clock is changed? Having mutable global state is just waiting for accidents to happen.
    – hoffmale
    8 hours ago













up vote
2
down vote










up vote
2
down vote









While I think the underlying idea is quite nice, the actual implementation and design has some issues.



Wrong Abstraction Level



Let's start with the less obvious one: How would you actually use Clock or BaseClock with std::chrono::high_resolution_clock or std::chrono::system_clock?



The simplest approach would be something akin to this:



struct HighResClock : BaseClock {
time_point now() override { return std::chrono::high_resolution_clock::now(); }
};


It seems so clean, so simple, and so easy. Except that it doesn't compile! That's because std::chrono::high_resolution_clock::time_point is not the same as BaseClock::time_point (and cannot easily be converted, if at all possible).



But: Do we actually need time_points in the public interface?



The only reason to expose time_point values is to extract time differences between them. But that only matters if arbitrary time_points are to be compared.




Technically, the time_point could be stored in some form. However, for many clocks, like std::chrono::steady_clock or std::chrono::high_resolution_clock, the epoch from when the clock are measuring their time offset can change between different executions of the same program (e.g. because the computer got rebooted).



This makes storing time_points, especially those not obtained from std::chrono::system_clock, rather useless. In that case, you'll likely need a calendar library (or similar) to get points of time in a storable format.




But in most cases, a simple Timer abstraction can fulfill all clock needs (comparing some time_points with some relation). A simple Timer interface could look like this:



struct timer {
// choose an appropriate duration type
using duration = std::chrono::duration<double>;

virtual ~timer() = default;

virtual void start() = 0;
virtual duration stop() = 0;
virtual duration tick() = 0; // to obtain multiple measurements from the same baseline
};

class steady_timer : public timer {
using clock = std::chrono::steady_clock;
using time_point = clock::time_point;

time_point start_time;
bool running;

public:
steady_timer() = default;

void start() override
{
start_time = clock::now();
running = true;
}

duration tick() override
{
return duration(clock::now() - start_time);
}

duration stop() override
{
auto elapsed = tick();
running = false;
return elapsed;
}
};


Now the only exposed part of the interface is the duration. And it is easily extensible to other time sources (e.g. Win32 QueryPerformanceCounter) or mockable.



Singleton



I really don't like the Clock singleton. Yes, it is easy to just ask a global clock. Yes, it is also easy to screw all code depending on this clock by changing the underlying instance.



For example, a test setting Clock to a mock but not restoring the original clock breaks all other tests that assume the default clock implementation - making test failure dependent on test execution order.



Instead, take a reference or pointer to a timer as parameter. This allows you to pass in a clock where needed, without changing (or corrupting) everyone elses timer.



Rewriting your test case:



class mock_timer : public timer {
std::vector<duration> measurements;
int counter = 0;

public:
mock_timer(std::initializer_list<duration> il) : measurements(il) {}

void start() override {}

duration tick() override
{
if(counter < measurements.size()) return measurements[counter++];
return measurements.back();
}

duration stop() override
{
return measurements.back(); // just example
}
};

void test_method(){
using namespace std::literals::chrono_literals;
mock_timer my_timer{ 10s };

testClass.methodUsingClock(my_timer);

// or, more likely:
testclass inst{my_timer};
inst.methodUsingClock();

REQUIRE(testClass.checkTimeout());
}





share|improve this answer












While I think the underlying idea is quite nice, the actual implementation and design has some issues.



Wrong Abstraction Level



Let's start with the less obvious one: How would you actually use Clock or BaseClock with std::chrono::high_resolution_clock or std::chrono::system_clock?



The simplest approach would be something akin to this:



struct HighResClock : BaseClock {
time_point now() override { return std::chrono::high_resolution_clock::now(); }
};


It seems so clean, so simple, and so easy. Except that it doesn't compile! That's because std::chrono::high_resolution_clock::time_point is not the same as BaseClock::time_point (and cannot easily be converted, if at all possible).



But: Do we actually need time_points in the public interface?



The only reason to expose time_point values is to extract time differences between them. But that only matters if arbitrary time_points are to be compared.




Technically, the time_point could be stored in some form. However, for many clocks, like std::chrono::steady_clock or std::chrono::high_resolution_clock, the epoch from when the clock are measuring their time offset can change between different executions of the same program (e.g. because the computer got rebooted).



This makes storing time_points, especially those not obtained from std::chrono::system_clock, rather useless. In that case, you'll likely need a calendar library (or similar) to get points of time in a storable format.




But in most cases, a simple Timer abstraction can fulfill all clock needs (comparing some time_points with some relation). A simple Timer interface could look like this:



struct timer {
// choose an appropriate duration type
using duration = std::chrono::duration<double>;

virtual ~timer() = default;

virtual void start() = 0;
virtual duration stop() = 0;
virtual duration tick() = 0; // to obtain multiple measurements from the same baseline
};

class steady_timer : public timer {
using clock = std::chrono::steady_clock;
using time_point = clock::time_point;

time_point start_time;
bool running;

public:
steady_timer() = default;

void start() override
{
start_time = clock::now();
running = true;
}

duration tick() override
{
return duration(clock::now() - start_time);
}

duration stop() override
{
auto elapsed = tick();
running = false;
return elapsed;
}
};


Now the only exposed part of the interface is the duration. And it is easily extensible to other time sources (e.g. Win32 QueryPerformanceCounter) or mockable.



Singleton



I really don't like the Clock singleton. Yes, it is easy to just ask a global clock. Yes, it is also easy to screw all code depending on this clock by changing the underlying instance.



For example, a test setting Clock to a mock but not restoring the original clock breaks all other tests that assume the default clock implementation - making test failure dependent on test execution order.



Instead, take a reference or pointer to a timer as parameter. This allows you to pass in a clock where needed, without changing (or corrupting) everyone elses timer.



Rewriting your test case:



class mock_timer : public timer {
std::vector<duration> measurements;
int counter = 0;

public:
mock_timer(std::initializer_list<duration> il) : measurements(il) {}

void start() override {}

duration tick() override
{
if(counter < measurements.size()) return measurements[counter++];
return measurements.back();
}

duration stop() override
{
return measurements.back(); // just example
}
};

void test_method(){
using namespace std::literals::chrono_literals;
mock_timer my_timer{ 10s };

testClass.methodUsingClock(my_timer);

// or, more likely:
testclass inst{my_timer};
inst.methodUsingClock();

REQUIRE(testClass.checkTimeout());
}






share|improve this answer












share|improve this answer



share|improve this answer










answered 11 hours ago









hoffmale

5,437835




5,437835












  • I understand your arguments But I see problems with that: Time is something global, so it makes sense for it being a singleton/global. Passing it to every class would require huge refactoring and passing things down in aggregates etc. which shows another problem: Your timer class cannot be reused! So e.g. a class that needs 2 timers cannot reuse the timer as it would restart. BUT: What if I use my design but change BaseClass::now to return a duration? Then the underlying clock does not matter as long is it returns "time since epoch" and is not changed while a Clock::time_point is held.
    – Flamefire
    10 hours ago










  • @Flamefire: I'm not sure if I am getting your whole argument. I don't think time is something global. Instead, everything has its own perspective on time. For example, a game might be using one clock for rendering and a different clock for logic updates. Why? Because if gameplay is paused (e.g. when entering a menu), the graphics should still continue to be rendered because otherwise the screen would freeze. // RE "time since epoch": When is epoch? What if the epoch changes because the clock is changed? Having mutable global state is just waiting for accidents to happen.
    – hoffmale
    8 hours ago


















  • I understand your arguments But I see problems with that: Time is something global, so it makes sense for it being a singleton/global. Passing it to every class would require huge refactoring and passing things down in aggregates etc. which shows another problem: Your timer class cannot be reused! So e.g. a class that needs 2 timers cannot reuse the timer as it would restart. BUT: What if I use my design but change BaseClass::now to return a duration? Then the underlying clock does not matter as long is it returns "time since epoch" and is not changed while a Clock::time_point is held.
    – Flamefire
    10 hours ago










  • @Flamefire: I'm not sure if I am getting your whole argument. I don't think time is something global. Instead, everything has its own perspective on time. For example, a game might be using one clock for rendering and a different clock for logic updates. Why? Because if gameplay is paused (e.g. when entering a menu), the graphics should still continue to be rendered because otherwise the screen would freeze. // RE "time since epoch": When is epoch? What if the epoch changes because the clock is changed? Having mutable global state is just waiting for accidents to happen.
    – hoffmale
    8 hours ago
















I understand your arguments But I see problems with that: Time is something global, so it makes sense for it being a singleton/global. Passing it to every class would require huge refactoring and passing things down in aggregates etc. which shows another problem: Your timer class cannot be reused! So e.g. a class that needs 2 timers cannot reuse the timer as it would restart. BUT: What if I use my design but change BaseClass::now to return a duration? Then the underlying clock does not matter as long is it returns "time since epoch" and is not changed while a Clock::time_point is held.
– Flamefire
10 hours ago




I understand your arguments But I see problems with that: Time is something global, so it makes sense for it being a singleton/global. Passing it to every class would require huge refactoring and passing things down in aggregates etc. which shows another problem: Your timer class cannot be reused! So e.g. a class that needs 2 timers cannot reuse the timer as it would restart. BUT: What if I use my design but change BaseClass::now to return a duration? Then the underlying clock does not matter as long is it returns "time since epoch" and is not changed while a Clock::time_point is held.
– Flamefire
10 hours ago












@Flamefire: I'm not sure if I am getting your whole argument. I don't think time is something global. Instead, everything has its own perspective on time. For example, a game might be using one clock for rendering and a different clock for logic updates. Why? Because if gameplay is paused (e.g. when entering a menu), the graphics should still continue to be rendered because otherwise the screen would freeze. // RE "time since epoch": When is epoch? What if the epoch changes because the clock is changed? Having mutable global state is just waiting for accidents to happen.
– hoffmale
8 hours ago




@Flamefire: I'm not sure if I am getting your whole argument. I don't think time is something global. Instead, everything has its own perspective on time. For example, a game might be using one clock for rendering and a different clock for logic updates. Why? Because if gameplay is paused (e.g. when entering a menu), the graphics should still continue to be rendered because otherwise the screen would freeze. // RE "time since epoch": When is epoch? What if the epoch changes because the clock is changed? Having mutable global state is just waiting for accidents to happen.
– hoffmale
8 hours ago


















 

draft saved


draft discarded



















































 


draft saved


draft discarded














StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f208273%2fmockable-clock-meeting-stdchrono-trivialclock-requirement-and-interface%23new-answer', 'question_page');
}
);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown