An Experiment In Scotch

I write to discover what I believe

Tag: TDD

Word Wrap Kata in Python

Last month at Dallas Hack Club, we did the Word Wrap Kata from Uncle Bob Martin’s “Clean Coder”. I got there a touch late and rapidly figured out that we were doing it in Ruby. Now, my Ruby skills are right up there with my Mandarin Chinese skills which is to say, I can’t even order a scotch or find the restroom so I quickly figured out that if I followed along, I’d be sitting in a puddle of pee wishing I was drunk. So I made the executive decision to ignore most everyone else and do it in parallel with the group but in Python since I can at least code like I’m drunk in Python.

My experience was surprisingly similar to the post linked above, e.g. I went down the hardest path trying to solve the wrong test. I’ve since gone back and deleted the code but the pseudocode went something like this:
[sourcecode language=”python”]Break text into a list using a list comprehension based on the length of the column
Start looking for words with spaces
Try to repiece things together based on the column length and the last space
Cry
[/sourcecode]

Clearly, this wasn’t going to work. About that time, we ran out of time and went to the Flying Saucer to drink beer and pretend like we weren’t geeks. But I decided to finish the kata this week during a slow period at work. Since I didn’t have Jerry there to talk me through how dumb I was, I started reading the post up until the point where it describes writing the wrong test and spending too much time trying to solve it. So I backed up, deleted everything and started down the easier path of solving all the non-space related issues first. Once I did that, and once I figured out that recursion was going to be a big help, the project really got easier.

The final solution is below:
[sourcecode language=”python”]
def wrap(text, num):

if len(text) <= num:
return text
elif text[num-1] == ‘ ‘:
return text[:num].rstrip() + ‘rn’ + wrap(text[num:], num)
elif text[:num].find(‘ ‘) > -1:
rightSpaceIdx = text.rfind(‘ ‘)
return text[:rightSpaceIdx] + ‘rn’ + wrap(text[rightSpaceIdx:].lstrip(‘ ‘), num)
else:
return text[:num] + ‘rn’ + wrap(text[num:].lstrip(), num)
[/sourcecode]

It’s fascinating how quickly the algorithm starts to come together when you write the correct test. The problem is, I’m terrible at all this so it’s going to take some time getting enough experience to correctly select what test to write next. I was writing a ton of code trying to solve a problem that was too hard and the solution I eventually would have come up with would have been effective but brittle.

The more I do TDD/BDD, the more I realize that it is *THE* way to develop software, especially if you’re working in a dynamic language. I’m currently working through the tutorials at Ruby Tutorials and it’s great to see that TDD is a fundamental part of the process. As I learned Python and Pylons, it was up to me to figure out best practices it seemed like and that’s workable but frustrating in the long run. I’m planning on doing more katas in an effort to improve my craft.

Pragmatic TDD

Tim Bray writes about when and how he does TDD. I think he’s exactly right when he talks about not doing TDD for green-field, beginning development. When I’m first writing a cut at a new project, I’ve got almost no idea what I’m doing. Doing TDD at this stage in the game is super expensive and really gets in the way of the exploration necessary for a new project. Having to rewrite my code as it evolves is expected but having to rewrite my code AND my tests because both were completely off base is pretty inefficient.

However, once things are pointed in the right direction, TDD is critical. It makes the incremental evolution of the software much safer, easier and efficient. Without the tests, iterating over your software is painful and liable to introduce bugs in code that was once working. TDD is at its best in the situation where the code, while not stable, is in a state of incremental evolution and not the general state of random upheaval that it is in the beginning of the project.

Like most things, pragmatism is useful. There are shades of gray around everything and saying that there is one true way makes no sense at all. TDD is useful as a tool but hammering every nail you see with it probably isn’t the best way to do things.

I’ve also started to see TDD as a tool to allow those of us who aren’t geniuses to actually produce good code. I’ve known a few true code geniuses in my career and like Picasso, their art tends to spring fully formed out of their heads. They may go back later and write tests around the code. However, they don’t need TDD to be good. For the rest of us, the incremental evolution that TDD supports and encourages helps us to write code that is functional and clean because we have to focus on the client of our software. Those of us who aren’t masters use TDD to fake it, to produce works of art that might not eventually hang on the walls of the Louvre but that make customers at art fairs all over the world reasonably happy.

TDD Efficiency

Microsoft Research has put out a paper with data that shows implementing TDD increases your development time by 15-35% but decreases your pre-release defects by 40-90%. This is in line with my experience and women’s intuition.

I haven’t quite made it through the entire paper but you can read it here.

Give Me An Assertion Vasily. One Assertion Only, Please

I was working through some broken unit tests this morning for the project I’m currently on and the second one in my list looked like this:

 [TestMethod]
        public void SelectTest()
        {
            Item item = session.SelectSingle(a => a.SkuNo == _item.SkuNo);

            Assert.IsTrue(item.Id > 0);
            Assert.AreEqual(item.Id, _item.Id);
            Assert.AreEqual(item.IsAutoReplenished, _item.IsAutoReplenished);
            Assert.AreEqual(item.Status, _item.Status);
            Assert.AreEqual(item.MaintenanceLevel, _item.MaintenanceLevel);
            Assert.AreEqual(item.Description, _item.Description);
            Assert.AreEqual(item.Type, _item.Type);
            Assert.IsTrue(item.LastAdjustmentDate.HasValue);
            Assert.AreEqual(item.LastAdjustmentDate.Value.Date,
               _item.LastAdjustmentDate.Value.Date);
            Assert.IsTrue(item.LastReceivedDate.HasValue);
            Assert.AreEqual(item.LastReceivedDate.Value.Date,
              _item.LastReceivedDate.Value.Date);
            Assert.IsTrue(item.LastReturnToVendorDate.HasValue);
            Assert.AreEqual(item.LastReturnToVendorDate.Value.Date,
              _item.LastReturnToVendorDate.Value.Date);

            Assert.IsTrue(item.Upcs.Count == 1);
            Assert.AreEqual(item.Upcs[0].Id, _item.Upcs[0].Id);
            Assert.AreEqual(item.Upcs[0].IsPrimary, _item.Upcs[0].IsPrimary);
            Assert.AreEqual(item.Upcs[0].UpcNo, _item.Upcs[0].UpcNo);
        }
}

An Item gets hooked up in the Initialize method of the test suite and then this test does 17 assertions on the item it gets back from the session. There are enough things wrong with this scenario to make me write a blog post about it. Which is saying something these days, if I’m not drunk blogging VPILFs and whining about briskets, I’m pretty much not writing. I digress.

First of all, it’s not really a unit test because it goes outside the boundary of the object under test by setting up an item, saving it to the database and then selecting it back out of the database for 17 assertions. The current project has a section for Functional/Integration tests and in all reality, this test probably belongs there.

Second, it’s poorly named. The names of test methods should read like documentation for the object under test. “SelectTest” tells me next to nothing about what is going on here and in fact, isn’t really what’s being tested at all. I have to read the entire test to know what’s being tested. In truth, this test is trying to verify certain properties are set on an Item. A correct name for this test is “IdIsGreaterThanZeroAndIdIsSameAsOriginalItemIdAndAutoReplenishedIsSameAsOriginalAutoReplenished
AndStatusIsSameAsOriginalStatusAndMaintenanceLevelIsSameAsOriginalMaintenanceLevel
AndDescriptionIsSameAsOriginalDescriptionAndTypeIsSameAsOriginalType
AndLastAdjustmentDateHasValueAndLastAdjustmentDateValueIsSameAsLastAdjustmentDateValue
AndLastReceivedDateHasValueAndLastReceivedDateValueIsSameAsOriginalLastReceivedDateValue
AndLastReturnToVendorDateHasValue
AndLastReturnToVendorDateValueIsSameAsLastReturnToVendorDateValue
AndHasOneUpcAndThatUPCsIdIsSameAsOriginalItemsUPCId
AndUPCIsPrimaryIsSameAsOriginalItemsUPCIsPrimary
AndUPCNoIsSameAsOriginalItemsUPCNo”

Whew. Deep breath. In through the nose, out through the mouth. Back with me? Good. This brings us to the final problem of this test and that is 17 @#$% ASSERTIONS IS TOO MANY FOR ONE @#$%^ TEST! Tests should be like objects, they should have one function and one function only. It’s amazing how many OO gurus there are out there who think tests like this are completely normal.

There are several reasons why you’d want one assertion per test. First, it makes for a very clean documentation of the object under test. Assuming all the test names are well-written, you can just read the tests and have a great idea what the object can and cannot do. Second, most unit test frameworks fail a test at the first failed assertion. If you have 17 of them, you don’t really know what’s broken about your object when the first one fails. You have to fix that first before running the test again. Finally, you’re really running multiple tests, you’re just doing it implicitly. Any time you have the option of doing something explicitly or implicitly, you should ALWAYS choose the former. Even if your framework runs all assertions, you’re doing so on object state that is no longer clean after the first assert failed. This isn’t giving you the kind of testing that you’re looking for.

In the end, test should have a single piece of functionality to test, they should be well-named and they should have a single assert. This will prevent some jerk from writing a blog post about your test that’s he’s having to fix 5 months after you wrote it. Even if you’re that jerk.

References: Write Maintainable Unit Tests That Will Save You Time And Tears
Avoid multiple asserts in a single unit test: revisited
Testing: One Assertion Per Test

TDD With Python and Pylons

I’ve been doing some development on a website using Python and the Pylons web framework. I’m trying to stay pretty strict with Test Driven Development (TDD) though I run into problems because I’m still a complete novice with Pylons and a half-complete novice with Python. In my experience so far, unit tests are moderately difficult in Pylons and turn out to be something closer to the bastard stepchild of a redneck unit test and a 5th Avenue socialite mom. I feel that way because the unit tests require the Pylons framework to be set up correctly. They also often go outside their boundaries and I haven’t looked into any mock frameworks, though I have the feeling that using a mock framework with a dynamic language like Python is probably a stupid thing to say in public.

Regardless, I have really started to enjoy working with Pylons and that stems from the actual functional tests that are available through the framework. Specifically, my development flow has been something like this:

  • Write new functional test of the web site
  • Run tests to see them error out. Typical error message is that an action isn’t implemented on the controller.
  • Implement the basic controller and the action but leave out the functionality under test.
  • Rerun the test to see it fail.
  • Implement the functionality necessary to get a passing test. This often includes implementing database tables, keys, getting SqlAlchemy set up to correctly map data to objects and creating new templates for HTML.

The functional tests are nice because while they aren’t confirming look and feel type stuff, they at least put the flow of the application under test. I’m a purist when it comes to having unit tests only test the code they are intended for but I’m not a purist when it comes to writing unit tests first as the only way to design the application. With a website like this, I’m pretty happy writing functional tests to drive out the design of the web site.

Here are some code snippets from my current website (try to ignore the fact that this looks like it might have something to do with horses and the Kentucky Derby, especially if you work for the NSA.)

First a test:

from darlydowns.tests import *
from darlydowns.model import meta
from darlydowns.model import horse


class TestHorseController(TestController):
    def test_index(self):
        # setting up a temp horse to make sure one exists for the test
        tempHorse = horse.Horse('my temp', 'my description')
        meta.Session.save(tempHorse)
        meta.Session.commit()

        response = self.app.get(url_for(controller='horse'))
        ## Test response...
        assert len(response.c.horses) > 0

        meta.Session.delete(tempHorse)
        meta.Session.commit()

Here we have a test that tests the response from a request for a URL that is handled by the controller “horse”. This controller grabs all the horses in the database and displays them in a table. The test saves a temp horse, gets the list, verifies the list contains at least 1 horse and then deletes the temp horse to clean up after itself.

Here’s the controller code that allows the test to pass:


import logging

from darlydowns.model import meta
from darlydowns.lib.base import *
from darlydowns.model import horse
from darlydowns.model.horse import Horse

log = logging.getLogger(__name__)

class HorseController(BaseController):

    def index(self):
        c.horses = [horse for horse in meta.Session.query(Horse).all()]
        return render('/horses.mako')

One of the beauties of Pylons is how little code is required to do something, once the project is set up. Here our HorseController has an action of “index” which is defined as a method. It grabs all the horses from the database and then uses a list comprehension to collect them into the c.horses variable. It then renders the template “horses.mako” which knows how to layout the web page using the horses found in the database.

Once this was done, I wrote code to save a horse, all driven out by the functional tests. I’ve been pretty happy with how the design is driven from these tests as it’s often quite clear where to proceed next in the application from the last test. Lots of times, other functionality comes up that doesn’t logically flow next but I just add that to a growing todo list in the project to make sure nothing is skipped.

Pylons takes a little getting used to, especially since I come from a static, everything in once solution sort of background. With Pylons, you need to learn Routes and Mako and SqlAlchemy but once you get your head around all those tools, it’s a joy to work with.

UPDATE: Welcome to everyone coming here from the Python subreddit. If you have any tips for testing using Pylons, feel free to drop me a comment. I’d love to hear about other people’s experiences.