lundi 27 juin 2016

Coding to an interface without an additional use of the interface aside from mocking for tests?

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:

  1. When I currently have no additional uses of an interface beside mocking/testing, does it still make sense to use this method?
  2. So now if I go ahead with "coding to an interface", which I only did for mocking/testing. If instead of passing around that interface, I just pass around what I want to mock(who inherits from that interface), am I still "coding to an interface"? I bring this up because sometimes this feels more readable.

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 then directly inherit from "Thing" for my mock class. This also in my code feels more readable, 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.

Aucun commentaire:

Enregistrer un commentaire