- If something requires only a method, there is no need to make it a class just to follow the "do one thing" metapher. "Do one thing" does not mean one should convert every function into a class. If something requires not more than one function, especially a small static function, just keep it as a function.
If something requires only a method, there is no need to make it a class just to follow the "do one thing" metapher. "Do one thing" does not mean one should convert every function into a class. If something requires not more than one function, especially a small static function, just keep it as a function.
In case one really needs to inject a function into a class for mocking purposes, one can use
std::function(C++ 11) for a constructor parameter to inject a functional object directly, without an extra polymorphic class. read_file_name_from_cmd_linelooks like a standalone static method for which it is probably acceptable to make it public for testing purposes. If you don't like having public methods inFooProjectwhich are not part of the required interface, you can probably moveread_file_name_from_cmd_lineinto a different class, maybe a general helper class for command line parsing.A constructor call like
std::ifstream file(file_name);does not require a test, this is part of the standard lib and should be tested by their authors. However, it might be a good idea to create a "seam" here (like aloadmethod which takes directly anistream) allowing to replace the "real" file stream creation by a "memory stream creation" for testing purposes.parse_ini_configcould be a public member ofIniConfig, which would make it simpler to test without any extra helper classes. A componentIniConfigcan usually be tested without mocking or DI.So given all the steps in
FooProject::loadhave unit tests, it is debatable whetherFooProject::loadneeds a unit test on its own, or if an integration test (using a real file) would be enough. But even for a unit test, I would suggest to only mock out the "outer world I/O", which means the file access andm_window_system.create_window. There is no need to create a mock for every intermediate step on its own.If the latter unit test fails for some input, and one cannot see the root cause immediately, then you one debug the test manually once, and identify the step or component which failed. Then should be to add a new unit test to the list of unit tests for that specific component which validates exactly that failure. There is usually no need to have the unit or integration test for
FooProject::loadshowing the specific failing component, that is the responsibility of the tests for the individual components.
In case one really needs to inject a function into a class for mocking purposes, one can use std::function (C++ 11) for a constructor parameter to inject a functional object directly, without an extra polymorphic class.
read_file_name_from_cmd_linelooks like a standalone static method for which it is probably acceptable to make it public for testing purposes. If you don't like having public methods inFooProjectwhich are not part of the required interface, you can probably moveread_file_name_from_cmd_lineinto a different class, maybe a general helper class for command line parsing.A constructor call like
std::ifstream file(file_name);does not require a test, this is part of the standard lib and should be tested by their authors. However, it might be a good idea to create a "seam" here (like aloadmethod which takes directly anistream) allowing to replace the "real" file stream creation by a "memory stream creation" for testing purposes.parse_ini_configcould be a public member ofIniConfig, which would make it simpler to test without any extra helper classes. A componentIniConfigcan usually be tested without mocking or DI.So given all the steps in
FooProject::loadhave unit tests, it is debatable whetherFooProject::loadneeds a unit test on its own, or if an integration test (using a real file) would be enough. But even for a unit test, I would suggest to only mock out the "outer world I/O", which means the file access andm_window_system.create_window. There is no need to create a mock for every intermediate step on its own.If the latter unit test fails for some input, and one cannot see the root cause immediately, then you one debug the test manually once, and identify the step or component which failed. Then should be to add a new unit test to the list of unit tests for that specific component which validates exactly that failure. There is usually no need to have the unit or integration test for
FooProject::loadshowing the specific failing component, that is the responsibility of the tests for the individual components.