Reputation: 23
I have been trying to apply TDD at work as of late and occasionally get hung up when I need to think about the best ways to mock. What I am working on involves a good deal of network requests and file system access so there doesn't seem to be anyway around mocking. From the GMOCK documentation my understanding is that my best options to mock classes are either through, "coding to an interface", or via templates.
Here are my 2 main questions regarding "coding to an interface", which afterward I will give examples to hopefully clarify what I am asking:
Sample code for #1...
class Thing {
bool IsInstalled(); // multiple filesystem calls, I want to mock this method
};
bool Install(vector<Thing>& thingsToInstall) // before "coding to an interface"
bool Install(vector<unique_ptr<IInstallable>>& thingsToInstall) // after "coding to an interface"
class Thing : public IInstallable {
bool IsInstalled() override;
};
class IInstallable {
virtual bool IsInstalled() = 0;
};
The behavior I am interested in mocking is whether or not these "Thing"s are installed or not. Based on that I may or may not do a network request(which I've already mocked). So instead of passing around a vector of "Thing" objects, I have to pass around a vector of unique_ptr to IInstallable(the behavior/interface I want to mock). It seems like a lot just so I can only test it and not even reuse the interface. I guess I want to know am I indeed "coding to an interface" here and this is just the way it is? Also could you elaborate on when it does and does not make sense to "code to an interface"?
Sample code for #2...
bool Install(vector<unique_ptr<IInstallable>>& thingsToInstall) // original "coding to an interface" method from above
So now that I am coding to an interface, seeing as how my only reason for passing around unique_ptrs to the interface was so I could test it. Is there any reason why I shouldn't just pass around unique_ptrs to my "Thing" which implements the IInstallable interface? I can then still directly inherit from "Thing" for my mock class. This also in my code feels more readable since I am passing around a type that feels more relevant to the surrounding code(Thing) instead of a more generic interface. But then am I even "coding to an interface" anymore? Or am I just completely destroying the purpose(besides testing) of "coding to an interface"?
This is what the final method would look like...
bool Install(vector<unique_ptr<Thing>>& thingsToInstall) // Thing still implements IInstallable, so I can mock Thing directly
Thank you anyone that takes the time to read this and respond! I greatly appreciate your help.
Upvotes: 1
Views: 121
Reputation: 4241
I think your main question is about this argument:
It seems like a lot just so I can only test it and not even reuse the interface.
But your coding to interface
example seems not practice. Defining an interface really requires careful design, rather than "I want to mock it so it should be an interface".
So back to your example, what you should really consider is, what is the common interface for class Thing
, yes it should have bool IsInstalled();
but what else?
Let's say your real class Thing
has two function in practice, then you're going to define your interface like this:
class IThing {
virtual bool IsInstalled() = 0;
virtual void DoSomething() = 0;
};
And then you can implement it:
class Thing : public IThing{
bool IsInstalled() override;
void DoSomething() override;
};
And use it like this:
bool Install(vector<unique_ptr<IThing>>& thingsToInstall);
Now you have the opportunity to:
IThing
in your functions;Thing
and pass IThing
to the functions in your production code;MockIThing
and pass IThing
to the functions in your test code.Upvotes: 1