News for hackers. Stuff that matters.
Re:The Pragmatics of TDD by danso on Wednesday March 06, 2013 @12:42PM (#5332448)
I've only recently started to use TDD, the biggest roadblock being the annoying steps it takes to set up the suite, directory structure (ok, that's pretty minor), and then properly use mocks and stubs. I sometimes forego the latter part.

I'm new to it but I find it an incredibly useful strategy. It forces orthogonality on me because I have to think how a function can be tested independently of the external objects that may use it...which causes me to challenge my initial assumptions and instincts about the overall application design.

In some sense, I guess, it is always frustrating to spend more time in the design stage than working with an actual prototype...but I find the medium-to-long term benefits to far outweigh the initial investment in time. And once the tests have been written, the actual functional code is almost trivial to write.

Even without the benefits TDD has in easing the maintenance/upgrade phase of a product, I find its effects on the design/prototype stage to be worth the effort alone.

Re:The Pragmatics of TDD by glenjamin on Wednesday March 06, 2013 @01:05PM (#5332654)
Ideally mocks and stubs should be used only when the thing you're mocking/stubbing is either slow or complex.

In general, just call the real thing and don't worry about it. Otherwise you'll expend loads of time and energy setting up fakes to test relatively simple code.

Re:The Pragmatics of TDD by jarrett on Wednesday March 06, 2013 @01:42PM (#5332927)
Agreed, and furthermore: Mocks don't verify that you're calling external code correctly. Suppose you think API method does X, but it actually does Y. You won't detect that with mocks. Maybe you have integration tests (i.e. tests of the entire system working in concert) to account for that, but I say, why not catch these things at every chance you get?
Re:The Pragmatics of TDD by LargeWu on Wednesday March 06, 2013 @02:12PM (#5333146)
>why not catch these things at every chance you get?

Because it's expensive. It takes time to write and maintain those tests. It takes time to run those tests. If you want to verify that API method works as assumed (and I assume you are talking about an API on an external system, but ultimately it doesn't really matter) then write a test specifically testing that API method.

Testing that method B also works while testing method A is, in my experience, the number one culprit of people writing bad tests. These tests are harder to set up, take longer to run, and are more prone to promoting brittle test code.

Test everything that's important to test, and nothing more. This is true whether you are talking about your entire system, or a single method.

Re:The Pragmatics of TDD by glenjamin on Wednesday March 06, 2013 @03:05PM (#5333456)
I agree, the thing I was trying to warn about is meticulously mocking out everything you possibly can to test every single method/class in complete isolation from the rest of the system.

It's very tempting to start doing this when you get into heavy unit testing, but I find in practice this adds more cost than value.

As an example, lets take some python code I just made up which formats some input into a message, throws the message onto the queue, and returns the message ID.

    class DelayedJob(object):
        def __init__(self, queue):
            self.queue = queue
        def add_job(self, task, params, priority=1):
            m = JSONMessage({
                task: task,
                params: params,
            })
            self.queue.add(m, priority)
            return m.getID()
It's pretty clear that the queue service needs to be mocked out, as you don't want to be talking to a real queue for a unit test (you'll probably want some sort of acceptance/integration test to cover this somewhere).

However, I have in the past been tempted to make the JSONMessage class injectable, and then inject a mock with a stubbed implementation of getID - I've often seen other people do this as well. The code required to set-up such a fake would be fairly verbose and add little in the way of extra clarity to the test. Since the class is fast and simple (in this scenario it's just a container) then I'd just leave the concrete class in use.