views:

204

answers:

2

In my question As a “mockist” TDD practitioner, should I mock other methods in the same class as the method under test?, Avdi answered "Personally I think that mocking on self is almost always a code smell. It's testing the implementation rather than the behavior." He may be right, but often I can't distinguish between the implementation and the behavior.

I have another example (in Python-style pseudo-code) that may lead to helpful answers:

class Consumer:

 def spec_dirpath:
  client = VCS.get_connection(self.vcs_client_name)
  client.sync()
  return client.dirpath()

 def spec_filepath:
  filepath = os.path.join(spec_dirpath(), self.spec_filename)
  if not os.path.exists(filepath):
   raise ConsumerException
  return filepath

 def get_components:
  return Components.get_components_from_spec_file(self.spec_filepath())

The idea here is that the get_components method calls the spec_filepath method in order to get a path to a file that the get_components_from_spec_file Components class method will read a list of components from. The spec_filepath method in turn calls spec_dirpath, which syncs the directory containing the spec file from the VCS system and returns the path to that directory. (Try not to look for bugs in this code--it's pseudo-code, after all.)

I'm looking for advice on how to test these methods...

Testing spec_dirpath should be quite straightforward. I can mock the VCS class and have it return a mock object and confirm the appropriate methods are called (and that the spec_dirpath method returns what the mock's dirpath method returns).

But if I don't mock spec_dirpath while testing spec_filepath, how do I avoid duplicating the same test code from the spec_dirpath code in the spec_filepath test? And if I don't mock spec_filepath while testing get_components, how do I avoid duplicating the test code from both spec_filepath and spec_dirpath?

+1  A: 

Usually in unit testing, behaviour refers to externally observable behaviour.

Using your example the observable behaviour would be the list of components that you get back from get. The fact that they come from a file is implementation, so I would advise building your tests around the list of components you get back without mocking the file retrieval as it is internal to the class, with setup code to provide an appropriate file.

The alternative would be to make the file which the components were loaded from a dependency for the class, e.g. make it a constructor parameter or method parameter, to allow the file to be specified externally to the class. In this case it would be external and so I would mock it to ensure you got consistent behaviour from it to ensure you're class was using it correctly.

marcj
+1  A: 

Unit testing works better with some form of dependency injection. In this case because you are creating the Client in the code you create a dependency in your test that requires some form of dynamic mock to cope with. (We'd use a partial mock in this case to mock our calls that create dependencies to avoid having to test those dependencies as well).

If you inject the dependency on startup (i.e. Pass in a client object) then you can mock it easily and not have major difficulties testing just the one class.

So you need either a partial mock or a dependency injection solution to meet those objectives.

Brody