Test-First vs. Test-After, Round 3

I post occasionally to JavaRanch, a “friendly” forum (it’s policed by moderators who cleanse any material deemed offensive). JavaRanch features a book-of-the-week discussion and giveaway. This week, it’s a pitch for the book, Next Generation Java Testing. The book so far appears to largely be a pitch for TestNG and an expected couple of rants against JUnit (version 3.8, for whatever odd reason, and not version 4) and TDD. I stopped reading it for now (I’ll finish it later) because I found Lasse Koskela’s book Test Driven more useful.

As expected, the JavaRanch discussions contain some allusions to the fact that it doesn’t matter whether or not you write (unit) tests first or last. I’ve written elsewhere on this subject many times, so I’ll add only a brief thought or two here.

I suppose it doesn’t matter, from a conceptual standpoint, if you do test firsts or tests after if you are an experienced professional developer. If you are good at design and structuring your code well, then there’s no reason you shouldn’t be able to write as many useful tests after you’ve already built the code.

But that’s not what really happens. In the real world**, 8 out of 10 developers aren’t so experienced or professional, and so most don’t care enough or know enough about design to structure their system right. And as soon as someone says, “you don’t really have to write tests for everything, and they can break and that’s ok,” the 80% end up thinking that these unit tests are largely a waste of time. So they–the developers and the tests–don’t get better.

The other reality is of course time. Without a disciplined approach, deadlines always get in the way of tests. Interruptions push unit tests outward, and they just don’t get done.

I believe that test-after is only for the true software development master who is close to expert level. For anyone else, it’s a recipe for wasted time and frustration. A better investment would be in automating your acceptance criteria.

That’s opinion. Test-after is unscientific and undisciplined, and that’s fact. I’m willing to accept that there may be something better, but test-after when-you-feel-like-it-and-can-figure-out-how-to-do-it is not it, and TDD is closer to following a scientific method. That too is fact. I’d rather look to advance the craft than make excuses why I’m too set in my ways to change.

** Sorry Tim.

 

Original Comments:

Real world. Arrrgh. Apology acknowledged. Not accepted. 😉

I have noticed that if *I* write the tests last, I don’t write the tests to spec, but to code. Likewise this applies to code I’ve seen others write. There really isn’t very much need for me to prove that the compiler works, ie that the code does what the code as-written does. I find in my experience that working the other way takes me in slightly different directions.

If the code would come out the same, and the tests were the same, then it wouldn’t matter. As they do not, it apparently does matter.

On that point, +1.

Hi Tim–See my more recent post here. Over the holidays, I chose to not write tests not as an exercise in proving my point, but out of sheer laziness–yet it ended up costing me far more time.

Aren’t you supposed to forgive others when they ask? 🙂

Stories and the Tedium of Daily Standups

In “Tools, Iterations, and Stories,” I talked about how you should “focus on implementing and completing stories, not iterations. If your iteration is 10 days, and you have 10 stories of 1 point each, you should have delivered one story by the end of the first day, and two stories by the end of the second day, and so on.”

Today I helped deliver training on agile estimation and planning. One topic that arose was the daily stand up. We quickly surmised, no surprise, that this group’s experiences with daily standups were negative. We discussed some of the reasons why these meetings might be so poorly received. As typical, their standup meetings went on much longer than 5-10 minutes. Reasons? Also typical: people didn’t literally stand up, the meetings lacked focus, and people tried to use them to solve problems instead of just identify them. Most people, rightly so, viewed these meetings as very costly.

In response, we talked about why daily standups might be useful. We discussed the importance of getting the entire team to communicate more frequently. Daily should be a bare minimum!

The other part of our discussion was around what should be said during a standup. One of the complaints was that the standups were boring and tedious. The teams were using the typically recommended elements: what did I accomplish, what am I working on, what might I need help with? You know the drill.

Then it struck me: a focus on completing iterations, not stories, was part of the problem, contributing to the tedium.

The classic mistake in an initial stab at doing agile is to treat each iteration as a mini-waterfall. Spend a day discussing requirements, spend a day or two on design, code it, then test it, then integrate it. A team will open most of its stories on day one, and on the last day of the iteration, most of these same stories will still be open. The team will struggle to close them out prior to iteration end. The article I wrote (see link above) talks about a better approach: initiate work on one or two stories, and move on only after these stories are completed. That allows for incremental delivery of business value throughout the iteration, and usually minimizes the amount of work at risk for the iteration.

A team following the first approach, where an iteration is a mini-waterfall, will have very little useful information to say during a daily standup:

  • “What did you work on yesterday?”
  • “The flim flam widget.”
  • “Is it going ok?”
  • “Sure, I guess so.”
  • “What are you doing today?”
  • “Same thing as yesterday. Probably tomorrow, too.”

Zzzz. The daily standup is drudgery, because not much is changing, and none of the information is reliable anyway. When asked where they’re at, a developer uses the old 80/20 rule. Week one in a two-week iteration, they’re probably 20% done, and week two, they’re 80% done. And during week one, most developers have the confidence that they’ll be done in time, even if they’re stumbling. We won’t find out that there are real problems with their commitment until (too) late in week two.

In contrast, here’s how a standup might go in a team that looks to complete stories, not iterations:

  • “What did you work on yesterday?”
  • Joe: “I started on the frizzbang story.”
  • “That’s supposed to be done sometime today, right? Are you on target?”
  • “Well, maybe not, I’m stuck on a strange exception. I could use help from someone who’s worked in this area.”
  • Jane: “OK, well, I helped complete the flim flam widget by finishing the GUI component, so I’m available.”
  • “So the flim flam is ready for testing?”
  • “Yup. Today I’ll go work with Joe, before I start on the festivus tool.”

The more I do agile, the more I find that a primary focus on (really) completing stories is the best path to success.

 

Comments:

I found out, that most of the time it happens this way, as people – who drive the stand-ups – create an impression what’s important and those who participate pick it up quickly and react according to the expectation. I have met few project managers, who are focused on delivering a real value, but instead are focused on detailed control.

But today I’ve heard one of the most stupid idea for daily stand-up. It was to divide the story into tasks and each day mark amount of percentage completed, so people could then present between each other their progress on daily stand-ups. This “thing” meant to focus people on completing their work.
Guess what ? The idea came out from the tool that draws the chart based on the amount of percentage completed.

Nice.

When I was talking about this with a group of people yesterday, one woman asked, “Isn’t this going to make all that task level tracking we do difficult?” Apparently they are putting all the tasks (which to them were “analysis,” “design,” “coding,” … all to be handed off from one person to the next) into their tracking tool.

I suggested that perhaps they wouldn’t feel compelled to track at that level if they could all just work together on a story or two and get them delivered every couple of days or so.

I repeated myself. I’m not positive it sank in even the second time. We’ll see. I could smell some fear in the room.

The more I hear such stories the more I’m convinced there’s little trust in people and the focus is on a tasks/iterations not stories.

Testing Getters and Setters?

You’ve heard many developers claim they don’t test getters and setters. Correct–you should probably not write direct tests for these things. The primary reason is that they do not (usually) represent behavior; a setter or getter is (usually) just a means of exposing an attribute.

Let me touch on a few points.

  • “Getters and setters can’t possibly break.” Wrong! Been there done that. Try misspelling the formal argument name in a setter, e.g. “X” instead of “x.” this.x = x; will compile (you might get a warning), but it will do nothing on execution. If you assume that this sort of code can never break, you will spend lots of time looking elsewhere for the problem–been there done that! 🙂 Still, this isn’t a compelling reason to write a direct test.
  • “Don’t test getters and setters” should probably be quantified with “directly.” More or less everything, in effect, should be test-driven. That is, code should not come into existence without first having a failing test. So, perhaps tests against a method in another class drive the need for the getter, and that’s fine. But you should never blindly add getters/setters to a class without a reason. (The code generator utilities in Eclipse and other tools should probably be painful to use, to dissuade you, and they sort of are.) If you use a dumb framework that insists on you creating getters/setters that aren’t directly called by your code, consider a better framework.
  • Many getters have interesting logic (e.g. lazy initialization), as do setters (although this is often a riskier design choice). I’m a firm believer in verifying that these “trivial” idioms actually work; I’ve seen enough broken initialization attempts. You should test-drive these, and probably directly so (and maybe even ensure they are comprehensively re-tested within the context that they are used).
  • I always write tests for constructors, for a few reasons. First, it’s a good, simple place to start. It allows you to get a quick test in place and build an instantiable class within a minute or two. Second, a class without tests often suggests to other developers that maybe we don’t need to worry about writing any tests for that class. “Oh yeah, I guess we need to add to the tests for this class.” Third, having to write constructor tests can discourage people from putting any complex logic in constructors, something that’s not usually a good thing to do. 🙂 Fourth, and most importantly, tests for constructors document all of the possible means of creating instances of a class, information that can be difficult to derive otherwise. You’re cheating your fellow developers by skimping on these tests.Having tests for my constructors means that I effectively test-drive getters, as they are the best means to verify construction.

So, should you test-drive getters and setters into existence? Yes, usually indirectly. As long as they get test-driven into existence, you’ll eventually find the problem if they hide a defect. Directly, only if the getters and setters are interesting.

 

Original Comments:

If someone asks me “Do you test setters/getters?” or “Do you change your methods from private to protected in order to test them?” it is a sign for me that this person is probably not doing test-first.

If you do TDD properly, you test behaviors, based on requirements (user stories, acceptance criteria). As you wrote – getters/setters don’t represent them. While making the class to fulfill the test getters and setters are created (if needed). That way they are automatically covered by tests. It is also true for private methods as they are usually the result of refactoring on the public/protected ones.

Atom