Mild pickle. I have a project which has components that are difficult to test/mock. It might look something like this:
class Contenxt;
class Server : public SomeOtherClass
{
public:
ServerPlugin(const Contex&) {
a.registerCallback([this](int i){ handleData(i); });
}
void handleData(int i)
{
int x = b.someFunc(i);
}
int getX() const { return x; }
private:
ClassA a;
ClassB b;
int x{0};
};
For ServerPlugin::getX() to be tested, we need some type of control over at least ClassA to trigger the asynchronous process.
Obviously this is a simplification but should illustrate the issue. Note that while my class can be structured in just about any way, the main caveat is that I'm locked into that constructor and can't get around that. My preferred method would be to have ClassA & ClassB be template parameters with a constructor that took a reference to each. My Unit test could use a test version of them w/ all functionality implemented. But, I can't do that.
So AFAIK, I have the following options.
- Modify the test framework to allow Friend classes access to private members. (I've seen this done before but is obviously somewhat controversial. Only listing for completeness.)
- ClassA & ClassB could be protected members, and inherit the ServerPlugin object
- Expose ClassA & ClassB via a public accessor. (This seems pretty terrible.)
- Make ClassA & ClassB public. (Even more terrible)
So the good news is that the testing framework will test my class end to end just fine, but to me I've left out at least a good integration test, if not a unit-test. Also relying on a rather ominous end to end test runner makes for some slow development, and potentially daunting tasks for pinpointing the location of a bug... not to mention less flexibility with multiple inputs.
So, I'm Wondering if there's something I've missed, or if anyone has an opinion either way.
Server
toServer<T_A, T_B>
, but to provide a template classGenericServer<T_A, T_B>
and atypedef GenericServer<ClassA, ClassB> Server;
, so the "older base" will not have to be changed . Another idea could be to utilize the preprocessor (which is a suggestion from Feathers' well known bool "Working effectively with Legacy code"). But I guess one has to know more of your original code to see how much effort this would mean in your codebase.