1

I have a class, which uses a timer, to do some time-dependent things. Now, I do create the timer inside the class:

class MyClass
{
public:
  Myclass(arg1, arg2, ...)
  :m_timer(new Timer(delay))

...

private:
   Timer* m_timer;
...

}

The timer has a few functions, like isRunning(), isExpired(), reset() However, when unitesting this class with google test framework, I cannot use the timer in my unit test, since it is a private member.

Another way of doing this, would be to create the timer in the factory for MyClass, and inject it. This way, I would be able mock the timer in my unittest and be able to use the three methods above in my unit test, to do a more extensive test for MyClass.

My question is, which would be the best practice? If I am doing the second alternative(injection), then it feels like I am adapting my class to the test, which is not right? On the other hand, I do get a class which is more testable. Is it possible to say which alternative is better in this case, an maybe in general?

4
  • 2
    "then it feels like I am adapting my class to the test" - if you shift your perspective, and think of the test not as just a test, but as a preliminary/experimental example of client code that's going to use your timer (a stand in for the actual, production client code), then tests let you define/explore the different ways the timer can be used (you can design how flexible or constrained you want this to be), and "adapting to the test" is then, really, adapting to different usage scenarios. 1/2 Commented Nov 18, 2021 at 10:09
  • Injecting a timer offers some flexibility - allowing client code to select a suitable timer implementation: a timer with specialized behavior, or of a different resolution, or one that can stretch or compress time (e.g., could be useful in a game), etc. 2/2 Commented Nov 18, 2021 at 10:09
  • 3
    Why would you not change a class for the sake of a test? Either the tests have business value (in that they help you create a defect-free deliverable) - then there is no reason to treat them as second-class code. Or they don't add business value - then there is no point in having them in the first place.. Commented Nov 18, 2021 at 11:14
  • 1
    @KilianFoth, "Why would you not change a class for the sake of a test?" An example is when someone makes a private method, public, because they want to test it. There are cases where it's the test that needs changing (eg to test via the public API) rather than the code needing changing.
    – David Arno
    Commented Nov 19, 2021 at 11:41

1 Answer 1

2

The underlying principle of TDD is "start with a (failing) test". By starting with a test, you are encouraged down the road of thinking about how you'd test you code before writing it. If you'd started with a test of MyClass, you'd have automatically injected that timer, because that is what's needed to allow easy testing.

The reason we write automated tests is because it makes code more robust and easier to maintain. In part it becomes easier to maintain the code as we can refactor/rewrite and rely on those tests to tell us we broke something. But it becomes easier in another way too: it encourages decoupling through injection in order to make those tests easier to write. And loosely coupled code is all too often easier to maintain whether you have tests or not.

... it feels like I am adapting my class to the test, which is not right?

Needing to adapt a class to a test is indeed a code smell: it's an alert that something is wrong. But in many cases, it soon becomes clear that it is the existing code that is not right and the need to adapt it to a test improves it. This is definitely not universal, but is true often enough to not fear the need to change your code just for a test.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.