tags:

views:

428

answers:

7

After reading Martin Fowler's Mocks Aren't Stubs, I've discovered I've been practicing TDD in the "mockist" fashion.

But I'm wondering if even in mockist TDD if one can take mocking too far.

Here's an updated example in Python-style pseudo-code:

def sync_path(self):
    if self.confirm_or_create_connection():
        self.sync(self.dirpath)

The confirm_or_create_connection() method creates a connection to a server.

I tested a method similar to this in two tests, both of which mock confirm_or_create_connection() and sync() (even though they're both methods in the same class). In one test the mock confirm_or_create_connection() returns True and the test confirms that sync() was called, and in the other the mock confirm_or_create_connection() returns False and the test confirms that sync() was not called.

Is this reasonable? Or should I mock the objects that confirm_or_create_connection() and sync() call? (I have other tests of both of these methods that already do this.)

Please don't answer the question by explaining that I should be practicing "classical" TDD instead. That's an answer to another question: Should I practice mockist or classical TDD?

+1  A: 

edited for the new example
To me it looks like you're stubbing confirm_or_create_connection, you're only interested in defining the return call and you're mocking sync, here you're interested in testing if it's really called. (I'll have to check if my definition of stubbing or mocking is the same as the fowler article you referenced. It's been some time since i've read it and I've been using rhinomocks in c# that might have it's own defenition of these terms :-) )

I think for what you're testing mocking and stubbing those calls is the right way to go. You don't want to test to fail if one of those functions has an error, there are other tests for that. You just want to test the operation of sync_path.

I agree with Avdi that this is kind of smelly. The tests are ok but your class might be doing too much.

Mendelt
I'll attempt to make my question more clear.
Daryl Spitzer
+3  A: 

Personally I think that mocking on self is almost always a code smell. It's testing the implementation rather than the behavior.

Avdi
But what about when a function doesn't return a result--only side effects? (Such as in my example above.)
Daryl Spitzer
Depending on the situation I would either stub/mock the objects that confirm_or_create_connection() calls, or I would put confirm_or_create_connection() on a contained object and substitute a stub implementation of that object at test time.
Avdi
A: 

Can you take mocking too far? I don't know about too far but it can be done badly such that you are actually testing the mocks instead of the code, or worse so that you have brittle tests.

But as long as you're writing good tests — tests that confirm your expected behavior, tests that are helping you write the code — then mock on!

Jeffrey Fredrick
+2  A: 

Edited for updated sample:

I see now. You have problems testing this class because it has design flaws. This class violates the single responsibility principle. It is doing two things. First, it's managing a connection to a database. It's also syncing.

You need a separate class to manage your database connection. This class will be a dependency of the class under test. The database connecting class can be faked when you unit test the class under test.

Formerly:

As a fellow interaction tester, consider refactoring if you have a need to do this. That class is probably doing too much.

Let me put it to you this way: calling a private method does not make an interaction.

This is one of the main points of TDD. When it hurts your design can be improved.

Matt Hinze
+1  A: 

Guessing wildly, it looks like the connection activity might belong in another object which should be delegated to, in which case you can mock that. I usually recommend against mocking one part of an object to test another part. It suggests that there are two concepts bolted together.

Steve Freeman
+4  A: 

The technique is called "mock objects", not "mock methods" for a reason. It encourages designs that divide the system into easily composed, collaborating objects and away from procedural code. The aim is to raise the level of abstraction so that you mostly program by composing objects and rarely write low-level control flow statements.

Nat
A: 

Here's a good read on it: "Principle: Don't modify the SUT" at http://xunitpatterns.com/Principles%20of%20Test%20Automation.html#Don

Modifying the class you're testing by mocking or stubbing portions of its implementation is a code smell. The refactoring to get away from it is to move the part you're mocking/stubbing to another class. That said its not always a terrible thing. Its a code smell but its not always inappropriate. For languages like C# or Java where you have good refactoring tools its easy to fix this code smell and I normally would (in C#, assuming Java is similar). I do a lot of development in Lua and Javascript though, where things are a little different. Creating and managing lots of classes in those languages are more difficult, so I am more tolerant of modifying the SUT in tests. Its always something I can fix later once the initial test coverage is there. It does require extra care.

Frank Schwieterman