DaedTech

Stories about Software

By

Intro to Unit Testing 9: Tips and Tricks

This, I’ve decided, is going to be the penultimate post in this series. I had originally targeted a 9 part series, finishing up with a “tips and tricks” post, the way you often see with technical books. But I think I’m going to add a 10th post to the series where I make the business case for unit testing. That seems like a more compelling wrap up to the series. So, stay tuned for one more after this.

This post is going to be a collection of tips and tricks for new and veteran unit testers.

Structure the test names for readability beyond just descriptive names.

The first step in making your unit tests true representation of business statements is to give them nice, descriptive names. Some people do this with “given, when, then” verbiage and others are simply verbose and descriptive. I like mine to read like conversational statements, and this creates almost comically long names like “GetCustomerAddress_Returns_Null_When_Customer_Is_Partially_Registered.” I’ve been given flack for things like this during my career and you might get some as well, but, do you know what? No one is ever going to ask you what this test is checking. And if it fails, no one is ever going to say “I wonder why the unit test suite is failing.” They’re going to know that it’s failing because GetCustomerAddress is returning something other than null for a partially registered customer.

When you’re writing unit tests, it’s easy to gloss over names of the tests the way you might with methods in your production code. And, while I would never advocate glossing over naming anywhere, you especially don’t want to do it with unit tests because unit test names are going to wind up in a report generated by your build machine or your IDE where as production methods won’t unless you’re using a static analysis tool with reporting, like NDepend.

But it goes beyond simply giving tests descriptive names. Come up with a good scheme for having your tests be as readable as possible in these reports. This is a scheme from Phil Haack that makes a lot of sense.
I adopted a variant of it after reading the post, and have been using it to eliminate duplication in the names of my unit tests. This consideration of where the test names will be read, how, and by whom is important. I’m not being more specific here simply because how you do this exactly will depend on your language, IDE, testing framework, build technology etc. But the message is the same regardless: make sure that you name your tests in such a way to maximize the value for those who are reading reports of the test names and results.

Create an instance field or property called “Target”

This one took a while to grow on me, but it eventually did and it did big time. Take a look at the code below, originally from a series I did on TDD:

[TestClass]
public class BowlingTest
{
	[TestClass]
	public class Constructor
	{

		[TestMethod, Owner("ebd"), TestCategory("Proven"), TestCategory("Unit")]
		public void Initializes_Score_To_Zero()
		{
			var scoreCalculator = new BowlingScoreCalculator();

			Assert.AreEqual(0, scoreCalculator.Score);
		}
	}

	[TestClass]
	public class BowlFrame
	{
		private static BowlingScoreCalculator Target { get; set; }

		[TestInitialize()]
		public void BeforeEachTest()
		{
			Target = new BowlingScoreCalculator();
		}

		[TestMethod, Owner("ebd"), TestCategory("Proven"), TestCategory("Unit")]
		public void With_Throws_0_And_1_Results_In_Score_1()
		{
			var frame = new Frame(0, 1);
			Target.BowlFrame(frame);

			Assert.AreEqual(frame.FirstThrow + frame.SecondThrow, Target.Score);
		}

		[TestMethod, Owner("ebd"), TestCategory("Proven"), TestCategory("Unit")]
		public void With_Throws_2_And_3_Results_In_Score_5()
		{
			var frame = new Frame(2, 3);
			Target.BowlFrame(frame);

			Assert.AreEqual(frame.FirstThrow + frame.SecondThrow, Target.Score);
		}

		[TestMethod, Owner("ebd"), TestCategory("Proven"), TestCategory("Unit")]
		public void Sets_Score_To_2_After_2_Frames_With_Score_Of_1_Each()
		{
			var frame = new Frame(1, 0);
			Target.BowlFrame(frame);
			Target.BowlFrame(frame);

			Assert.AreEqual(frame.Total + frame.Total, Target.Score);
		}

		[TestMethod, Owner("ebd"), TestCategory("Proven"), TestCategory("Unit")]
		public void Sets_Score_To_Twenty_After_Spare_Then_Five_Then_Zero()
		{
			var firstFrame = new Frame(9, 1);
			var secondFrame = new Frame(5, 0);

			Target.BowlFrame(firstFrame);
			Target.BowlFrame(secondFrame);

			Assert.AreEqual(20, Target.Score);
		}

		[TestMethod, Owner("ebd"), TestCategory("Proven"), TestCategory("Unit")]
		public void Sets_Score_To_25_After_Strike_Then_Five_Five()
		{
			var firstFrame = new Frame(10, 0);
			var secondFrame = new Frame(6, 4);

			Target.BowlFrame(firstFrame);
			Target.BowlFrame(secondFrame);

			Assert.AreEqual(30, Target.Score);
		}
	}

	public class BowlingScoreCalculator
	{
		private readonly Frame[] _frames = new Frame[10];

		private int _currentFrame;

		private Frame LastFrame { get { return _frames[_currentFrame - 1]; } }

		public int Score { get; private set; }

		public void BowlFrame(Frame frame)
		{
			AddMarkBonuses(frame);

			Score += frame.Total;
			_frames[_currentFrame++] = frame;
		}

		private void AddMarkBonuses(Frame frame)
		{
			if (WasLastFrameAStrike()) Score += frame.Total;
			else if (WasLastFrameASpare()) Score += frame.FirstThrow;
		}

		private bool WasLastFrameAStrike()
		{
			return _currentFrame > 0 && LastFrame.IsStrike;
		}
		private bool WasLastFrameASpare()
		{
			return _currentFrame > 0 && LastFrame.IsSpare;
		}
	}
}

If you look at the nested test class corresponding to the BowlFrame method, you’ll notice that I have a class level property called Target and that I have a method called “BeforeEachTest” that runs at the start of each test and instantiates Target. I used to be more of a purist in wanting all unit test methods to be completely and utterly self-contained, but after a while, I couldn’t deny the readability of this approach.

Using “Target” cuts out at least one line of pointless (and repetitive) instantiation inside each test and it also unifies the naming of the thing you’re testing. In other words, throughout the entire test class, interaction with the class under test is extremely obvious. Another ancillary benefit to this approach is that if you need to change the instantiation logic by, say, adding a constructor parameter, you do it one place only and you don’t have to go limping all over your test class, doing it everywhere.

I highly recommend that you consider adopting this convention for your tests.

Use the test initialize (and tear-down) for intuitive naming and semantics.

Along these same lines, I recommend giving some consideration to test initialization and tear-down, if necessary. I name these methods BeforeEachTest and AfterEachTest for the sake of clarity. In the previous section, I talked about this for instantiating target, but this is also a good place to instantiate other common dependencies such as mock objects or to build friendly instances that you pass to constructors and methods.

This approach also creates a unified and symmetric feel in your test classes and that kind of predictability tends to be invaluable. People often debug production code, but are far more likely to initially contemplate unit tests by inspecting them, so predictability here is as important as it is anywhere.

Keep Your Mind on AAA

AAA. “Arrange, Act, Assert.” Think of your unit tests in these terms at all times and you’ll do well (I once referred to this as “setup, poke, verify.“). The basic anatomy of a unit test is that you setup the world that you’re testing to exist in some situation that matters to you, then you do something, then you verify that what you did produced the result you expect. A real world equivalent might be that you put a metal rod in the freezer for 2 hours (arrange), take it out and stick your tongue on it (act), and verify that you can’t remove your tongue from it (assert).

If you don’t think of your tests this way, they tend to meander a lot. You’ll do things like run through lists of arguments checking for exceptions or calling a rambling series of methods to make sure “nothing bad happens.” This is the unit test equivalent of babbling, and you don’t want to do that. Each test should have some specific, detailed arrangement, some easily describable action, and some clear assertion.

Keep your instantiation logic in one place

In a previous section, I suggested using the test runner’s initialize method to do this, but the important thing is that you do it, somehow. I have lived the pain of having to do find and replace or other, more manual corrections when modifying constructors for classes that I was instantiating in every unit test for dozens or even hundreds of tests.

Your unit test code is no different than production code in that duplication is your enemy. If you’re instantiating your class under test again and again and again, you’re going to suffer when you need to change the instantiation logic or else you’re going to avoid changing it to avoid suffering, and altering your design to make copy and paste programming less painful is like treating an infected cut by drinking alcohol until you black out and forget about your infected cut.

Don’t be exhaustive (you don’t need to test all inputs — just interesting ones)

One thing I’ve seen occasionally with people new to unit testing and especially getting their heads around TDD is a desire to start exhaustively unit testing for all inputs. For instance, let’s say you’re implementing a prime number finder as I described in my Pluralsight course on NCrunch and continuous testing. At what point have you written enough tests for prime finder? Is it when you’ve tested all inputs, 1 through 10? 1 through 100? All 32 bit integers?

I strongly advise against the desire to do any of these things or even to write some test that iterates through a series of values in a loop testing for them. Instead, write as many tests as you need to tease out the algorithm if you’re following TDD and, in the end, have as many tests as you need to cover interesting cases that you can think of. For me, off the top (TDD notwithstanding), I might pick a handful of primes to test and a handful of composite numbers. So, maybe one small prime and composite and one large one of each that I looked up on the internet somewhere. There are other interesting values as well, such as negative numbers, one, and zero. I’d make sure it behaved correctly for each of these cases and then move on.

It might take some practice to fight the feeling that this is insufficient coverage, but you have to think less in terms of the set of all possible inputs and more in terms of the set of paths through your code. Test out corner cases, oddball conditions, potential “off by one” situations, and maybe one or two standard sorts of inputs. And remember, if later some kind of bug or deficiency is discovered, you can always add more test cases to your test suite. Your test suite is an asset, but it’s also code that must be maintained. Don’t overdo it — test as much as necessary to make your intentions clear and guard against regressions, but not more than is needed.

Use a continuous testing tool like NCrunch

If you want to see just how powerful a continuous testing tool is, check out that Pluralsight video I did. Continuous testing is game changer. If you aren’t familiar with continuous testing, you can read about it at the NCrunch website. The gist of it is that you get live, real-time feedback as to whether your unit tests are passing as you type.

Let that sink in for a minute: no running a unit test runner, no executing the tests in the IDE, and not even any building of the code. As you type, from one character to the next, the unit tests execute constantly and give you instantaneous feedback as to whether you’re breaking things or not. So, if you wander into your production code and delete a line, you should expect that you’ll suddenly see red on your screen because you’re breaking things (assuming you don’t have useless lines of code).

I cannot overstate how much this will improve your efficiency. You will never go back once you get used to this.

Unit Tests Instead of the Console

Use unit tests instead of the console or whatever else you might use to do experimentation (get comfortable with the format of the tests). Most developers have some quick way of doing experiments — scratchpads, if you will. If you make yours a unit test project, you’ll get used to having unit tests as your primary feedback mechanism.

In the simplest sense, this is practice with the unit test paradigm, and that never hurts. In a more philosophical sense, you’re starting to think of your code as a series of entry points that you can use for inspection and determining how things interact. And that’s the real, longer term value — an understanding that good design involves seams in the code and unit tests let you access those seems.

Get familiar with all of the keyboard shortcuts

Again, this is going to vary based on your environment, but make sure to learn whatever keyboard shortcuts and things your IDE offers to speed up test management and execution. The faster you are with the tests, the more frequently you’ll execute them, the more you’ll rely on them, and the more you’ll practice with them.

Your unit test suite should be a handy, well-worn tool and a comfortable safety blanket. It should feel right and be convenient and accessible. So anything you can do to wear it in, so to speak, will expedite this feeling. Take the time to learn these shortcuts and practice them — you won’t regret it. Even if you have a continuous testing tool, you can benefit from learning the most efficient way to use it. Improvement is always possible.

General Advice

Cliche as it may sound and be, the best tip I can give you overall is to practice, practice, practice. Testing will be annoying and awkward at first, but it will become increasingly second nature as you practice. I know that it can be hard to get into or easy to leave by the wayside when the chips are down and you’re starting at a deadline, but the practice will mitigate both considerations. You’ll grow less frustrated and watch the barriers to entry get lower and, as you get good, you won’t feel any inclination to stop unit testing when the stakes are high. In fact, with enough practice, that’s when you’ll feel it’s most important. You will get there with enough effort — I promise.

By

Uber-Architects: The Building Metaphor Is Dead

Building Bad Software is Like Building a Tower

A little over a year ago, I wrote a post explaining how you can use the metaphor, “building software is like building a tower” to help you write bad software. The idea was that building something like a skyscraper requires insane amounts of planning because the actual act of building is laborious, time-consuming, and expensive, and also pretty much impossible to change once you get going. Furthermore, the real brains of the operation is required for the up-front planning, which is then done in such detail that the actual construction is a pretty straight-forward task that doesn’t require a whole lot of thinking — just following of detailed instructions and a practiced knack for skills like assembling plumbing, taping drywall joints, etc.

Software really only follows this pattern if it’s awful. If you were to describe a project you were working on by saying, “it’s important that we get everything right from the get-go because once we get started, this system is going to be so set and rigid that change is impossible,” wouldn’t you be a little alarmed and/or defeated? And what about the idea that the developer is so wildly different from the architect that they have two entirely separate vocational training paths (in the case of buildings, architectural studies versus carpentry trade school or apprenticeship). Is planning how to write software so very different than writing software?

I believe you’d be pretty hard pressed to continue to like this metaphor when you give it a lot of thought. But that hasn’t stopped the metaphor from being iconic in our industry, to the extent that it still vestigially governs roles, titles, career paths, and team behavior. Even though building software is nothing like structural construction, we continue to have a very real role/title called “Architect” that is responsible for coming up with documentation that looks suspiciously like a set of blueprints so that the lower paygrade laborers can toil away while he supervises.

Is this the best role and set of duties for the person called “architect” — the person on the team who has probably gotten to the position by being a good developer for a long time (or, more cynically, by being a mediocre and tenured Expert Beginner)? Should the result of spending years getting good at writing software be that you get to be in charge of the software by writing less of it? Are the architects of our buildings the people who are really, really good at pouring concrete and hanging drywall? Obviously not. And while we’re at it and this frayed metaphor is truly breaking down, should we even call them architects any more?

A Bit of Philosophy

I think that those of us who occupy the role or aspire to it should perhaps start striving to become post-architects or Uber-Architects. I’m borrowing this latter term from Friedrich Nietzsche, a philosopher and sporter of an awesome mustache that wrote about what he called the “Ubermensch,” which I believe translates from German to something along the lines of “over-man.” Nietzsche’s concepts in “Thus Spake Zathustra” are extremely nuanced and layered, but I’ll summarize what I took out of it when I read it and how I think it relates.

Nietzsche

You might know Nietzsche as the philosopher who famously said, “God is dead,” and he said that in this book. I believe that this is largely interpreted as a profoundly and stridently atheist sentiment, but that interpretation is one that ignores the context of the work and his other works. He was looking at a world (he lived in Europe during the 1800s) where morality had long been a matter simply dictated by the tenets of Christianity, but also in a world where the rejection of religion was becoming increasingly common. Nietzsche wasn’t gloating over the corpse of God; he was expressing worry that a growing atheist/agnostic segment of the population would opt for nihilism in the absence of any religion and that society would become dominated by what he called something like “last man,” a rather wretched creature interested only in its own comfort and with no direction or broader purpose. He was saying, “I don’t care for your religion, but if you take it away, I’m worried that things will get a lot worse.”

From Nietzsche’s perspective, 19th century Europe was in trouble and the path forward was for mankind to become the “Ubermensch,” a version of man that was capable of supplying himself with all of the things for which religion had previously been responsible. Basically, he should do good in life because it’s good to do good rather than because he’ll be in trouble if he doesn’t. He should define his own purpose and leave his mark on the world because it’s the right thing to do and the highest calling for an individual would be to leave a mark on history for the better. In the absence of the previous and declining moral order, a new, sustainable one had to be defined, so his argument went (or at least my recollection of my reading and understanding of it).

Forget the religious angle here in a discussion of software. I’m not interested in discussing the merits of Nietzsche’s religious beliefs or lack thereof here. But I am interested in relating his perception of the world to our situation. Throughout the history of software development, our roles have been defined by this now flagging and failing metaphor of “software is like building a tower.” We’ve mimicked construction in our historical approach with lengthy and detailed planning along with the division of labor. We’ve gone so far as to borrow the titles for the roles in that line of work and appropriate them for ourselves. Your software group has to have an “architect” that will make the “blueprints” for the software. But that’s absurd and people are starting to realize it (see the growth of agile methodologies that have no equivalent at all in the construction world).

The danger then becomes what happens in the absence of that metaphor. Do we adopt improvident and cavalier approaches to software architecture, swinging the other way on the “lots of planning versus no planning” pendulum? Do we abolish the role of any kind of technical leader and make all software development groups pure democracy? Do the former architects or developers in general become “last architects,” just nihilistically banging out whatever code seems interesting or gets them out the door at 5 without worrying over the future or the needs of the business?

Emergence of the Uber-Architect

This is where the Uber-Architect comes in. The Uber-Architect deals not in blueprints and orders from on high but from leadership by example in the trenches. Uber-Architecture isn’t about web services, database technologies, N-Tiers or enterprises, but about teaching and demonstrating important fundamental concepts of the craft: abstractions, design trade-offs, and implementation patterns. Uber-Architects don’t create a bunch of rules and enforce them across large organizations for consistency’s sake, like a foreman with a clipboard overseeing hundreds of fungible laborers. They pick up the hammers and nails and work along side those workers, showing them how it’s done, building the thing together, and making those around them better until it is no longer a fungible collection of workers, but a humming, autonomous machine that’s more than the sum of its parts. They leave their mark on the group not because they’re “architect” but because it’s the right thing to do, and it’s something of which they can be proud.

So what do teams look like when all of this comes to pass? I don’t know, exactly. But I think we’re finding out. I think that we’re going to see more and more teams with flatter structures, less worried about seniority, and more buying into the agile concept of self-organizing teams. And on those teams, there is no architect because people doing a good job of building software won’t assemble into organizational structures that are ill suited to building software. On these teams, there will only be Uber-Architects, who don’t hold a position afforded to them by 15 years in with the company, but who hold a place of respect among their peers due to ability and vision, and who create design concepts that make the lives of those around them easier and the skills of those around them sharper.

If this sounds overly idealistic, perhaps it is, but that’s because I view it as a goal and something to start reaching toward. And besides, with all of the cynical posts I make about Expert Beginners and overrated people and whatnot, some starry-eyed optimism probably balances out the cosmic scales a bit.

By

You Should Subscribe to Tech Podcasts

For the first post of 2014, I thought I’d make it a quick one, largely due to the fact that I haven’t had a lot of time to catch my breath over the last few weeks and am thus short on posts in my drafts. A while back, I wrote a post about multi-tasking where I described that I listen to podcasts on the drive to and from work each day. I thought I’d list some podcasts that you might want to check out. I find them valuable, anyway.

I have an app on my phone called Doggcatcher (I think it might be Android only). It’s great for organizing podcasts to which you want to subscribe and playing them as if you were listening to a radio show. With the bluetooth setup in my car, this turns out to be perfect: one ends, and the next one automatically starts without me intervening. New episodes download automatically and listened-to ones vanish automatically from your phone’s drive. Here is my list:

  1. .NET Rocks, a frequently released, professionally done show about all things .NET.
  2. Hanselminutes, a weekly technology talk show with Scott Hanselman
  3. This Developer’s Life, a sporadic personal evaluation of software developers’ lives (Rob Conery and Scott Hanselman)
  4. Polymorphic Podcast is a developer podcast from Craig Shoemaker (I don’t think it’s made anymore, but it was really good when it was, and I’m hoping it comes back)
  5. Herding Code, a group of prominent technologists conduct interviews with people doing cool things in the industry.
  6. The Java Posse, a show about all things Java, that helps me from getting too .NET-centric these days.
  7. The Stack Exchange Podcast will be familiar if you participate in the stack exchange Q&A sites.
  8. Deep Fried Bytes is another tech podcast, “with a southern flavor” (though I don’t personally consider that to be a draw, per se — it’s an interesting show on its own).
  9. Yet Another Podcast, the one I deliberately saved for last due to its name.  This is a last, but not least situation — definitely interesting.

I also listen to the Freakonomics podcast, due to a mild obsession with incentives and outcomes that I’ve had for the last couple of years, but I omitted that from the general theme of developer podcasts.

If you’re a developer and interested in improving your craft, I’d highly recommend subscribing to some podcasts.  This is an excellent array of them with lots of good information, in my opinion.  Perhaps there are others that you’d prefer, however.  Just find some and listen.

Podcasts are a great way to passively assimilate information.  You don’t need to concentrate heavily or even pay attention all the way through, though it’s certainly preferable.  These podcasts touch lightly on a wide variety of topics and the end-result is that they’ll make you vaguely aware of a lot of things that could be useful.  You’re not going to come away from your morning commute suddenly fluent in a new programming language, but when your peers are talking about writing a distributed, publish/subscribe utility that can dictate message routes, you can think to yourself, “I’m pretty sure something like that exists…. and that they talked about it on one my my podcasts… let me go google it.”  In fact, over the years that I’ve kept up with podcasts, I can’t tell you how many wheels I’ve avoided re-inventing.

So, go get yourself a podcast app if that’s your thing.  Or if not, just visit the sites periodically for new episodes.  Whatever approach you take, turn yourself on to this pasive way of keeping current with the industry that you can keep up with during life’s natural downtime.  I’m pretty sure you won’t regret it.