views:

488

answers:

3

Recently I've been experimenting with TDD while developing a GUI application in Python. I find it very reassuring to have tests that verify the functionality of my code, but it's been tricky to follow some of the recommened practices of TDD. Namely, writing tests first has been hard. And I'm finding it difficult to make my tests readable (due to extensive use of a mocking library).

I chose a mocking library called mocker. I use it a lot since much of the code I'm testing makes calls to (a) other methods in my application that depend on system state or (b) ObjC/Cocoa objects that cannot exist without an event loop, etc.

Anyway, I've got a lot of tests that look like this:

def test_current_window_controller():
    def test(config):
        ac = AppController()
        m = Mocker()
        ac.iter_window_controllers = iwc = m.replace(ac.iter_window_controllers)
        expect(iwc()).result(iter(config))
        with m:
            result = ac.current_window_controller()
            assert result == (config[0] if config else None)
    yield test, []
    yield test, [0]
    yield test, [1, 0]

Notice that this is actually three tests; all use the same parameterized test function. Here's the code that is being tested:

def current_window_controller(self):
    try:
        # iter_window_controllers() iterates in z-order starting
        # with the controller of the top-most window
        # assumption: the top-most window is the "current" one
        wc = self.iter_window_controllers().next()
    except StopIteration:
        return None
    return wc

One of the things I've noticed with using mocker is that it's easier to write the application code first and then go back and write the tests second, since most of the time I'm mocking many method calls and the syntax to write the mocked calls is much more verbose (thus harder to write) than the application code. It's easier to write the app code and then model the test code off of that.

I find that with this testing method (and a bit of discipline) I can easily write code with 100% test coverage.

I'm wondering if these tests are good tests? Will I regret doing it this way down the road when I finally discover the secret to writing good tests?

Am I violating the core principles of TDD so much that my testing is in vain?

A: 

Unit tests are really useful when you refactor your code (ie. completely rewrite or move a module). As long as you have unit tests before you do the big changes, you'll have confidence that you havent forgotten to move or include something when you finish.

etchasketch
+4  A: 

If you are writing your tests after you've written your code and making them pass, you are not doing TDD (nor are you getting any benefits of Test-First or Test-Driven development.. check out SO questions for definitive books on TDD)

One of the things I've noticed with using mocker is that it's easier to write the application code first and then go back and write the tests second, since most of the time I'm mocking many method calls and the syntax to write the mocked calls is much more verbose (thus harder to write) than the application code. It's easier to write the app code and then model the test code off of that.

Of course, its easier because you are just testing that the sky is orange after you made it orange by painting it with a specific kind of brush. This is retrofitting tests (for self-assurance). Mocks are good but you should know how and when to use them - Like the saying goes 'When you have a hammer everything looks like a nail' It's also easy to write a whole load of unreadable and not-as-helpful-as-can-be tests. The time spent understanding what the test is about is time lost that can be used to fix broken ones.

And the point is:

  • Read Mocks aren't stubs - Martin Fowler if you haven't already. Google out some documented instances of good ModelViewPresenter patterned GUIs (Fake/Mock out the UIs if necessary).
  • Study your options and choose wisely. I'll play the guy with the halo on your left shoulder in white saying 'Don't do it.' Read this question as to my reasons - St. Justin is on your right shoulder. I believe he has also something to say:)
Gishu
A: 

Please remember that TDD is not a panaceum. It's hard, it's supposed to be hard, and it's especially hard to write mocking tests "in advance".

So I would say - do what works for you. Even it's not "certified TDD". I do basically the same thing.

You may want to provide your own API for GUI that would sit between controller code and GUI library code. That could be easier to mock, or you can even add some testing hooks to it.

Last but not least, your code doesn't look too unreadable to me. Code using mocks is generally harder to understand. Fortunately in Python mocking is much easier and cleaner than i n other languages.

phjr