So you went to work for the cool company that wooed you with promises of cutting edge technologies and techniques. In the interview, they told you that they are agile and unit test everything. You may or may not have been in an agile environment before, but the important thing you are enthusiastic about joining a team that truly gets software development. You tested on your previous job, even using JustMock to write better tests. You promise you can be agile yourself and quickly adopt their practices. You’re immediately hired.
Many of you have been there… maybe you’re there right now.
It takes a few days to receive your workstation, and you find most of the development software isn’t set up. A coworker gives you the instructions, and by the end of the day you find yourself still struggling to connect to the version control server.
The next day, you ask your manager about your problem. It turns out that the person in charge of the version control and build servers left a few months back; you’re the replacement. Further inquiries lead to a startling truth: no one has administrative access.
Remembering that you replaced the version control administrator, you find the user name and password taped under your desk!
You pull down the source code, and it quickly becomes apparent that you’re lost. It’s a large project, and the unit tests are completely unreadable, seemingly without logic or organization. “Something is better than nothing,” you think as you run all the tests.
It turns out that the vast majority of the tests are ignored; so much for that approach! You remove the Ignore attributes and try again. It seems to be taking a while, and it’s past time to go out. You decide to check on it in the morning even though it’s a Saturday.
When you arrive at work the next morning you see a fair number of cars. The company stressed having a healthy life/work balance, so you thought mandatory weekend work was rare. You make your way to the office and discover most of your team is here, frantically working.
“Hey, it’s good for you to finally join us. There was a catastrophe last night. Our primary data storage was corrupted beyond recovery and the backups aren’t restoring successfully. We suspect hackers.”
“Well, most likely some teenagers who are good at breaking into computers. They manipulated a lot of data, and what we were able to track down is obviously fake. I mean, who names a child Little Teapot.”
That is rather suspicious. At your workstation, you found that the unit tests took an hour to run… good thing you left the night before. You search the code base for “Little Teapot” and find that it’s used in one of the tests you re-enabled.
You must hate unit testing… I know I do.
What to Do
If your employment continues, you may want to apply best practices to the unit test projects. Here are three important aspects you should consider to get started.
The reason the finale in my story happened as it did was quite simply due to a test not being isolated. The tests that were ignored were writing test data to a database – the production database! To isolate the test, you need to remove dependencies. If one subsystem calls another, a stand-in object must take the place of the dependent subsystem in the system-under-test. When you run the test, if a substitute was expected to be making calls to a database or other services, it can pretend to do the call then return results that you want the system-under-test to receive.
This is easy to do with Telerik JustMock. I wrote about using JustMock to get you started in From Legacy to Dependency Injection.
Slow unit tests cause lost productivity. While you’re waiting on your tests to run, it may be difficult to get much else done. Worse still, you may find yourself reading blogs until well-after they finish running. Slow tests are typically caused by the lack of isolation, and the best way to handle this issue is to isolate any calls outside of the system.
Hard to Understand Test Code
There are many patterns in development, and the Arrange-Act-Assert pattern (also referred to the AAA pattern) will help clean up your tests. These steps were described by William C. Wake in 2003.
- Arrange all necessary preconditions and inputs.
- Act on the object or method under test.
- Assert that the expected results have occurred.
When testing certain types of object, you may find that other patterns are more suitable. These are usually slight variations of the AAA pattern accounting for specific behaviors. Some mocking frameworks push you towards different pattern that ends up complicating the code. This is not the case with JustMock, which enables you to stick to the Arrange-Act-Assert pattern to maintain descriptive tests.
Don’t Hate the Game, Hate the Player
If you have entered a company with poor unit testing practices, you will likely encounter other problems. Many practices and methodologies follow each other, and improper implementation for one item may encourage improper implementation in another. Many companies are successful with different practices in place, and none of this is one-size-fits-all. Steve Forte and Joel Semeniuk have a great presentation on this called The Agile Buffet Table. The most important thing is to regularly analyze your practices and determine if revision is necessary or if everything is okay. And please, realize it’s bad if no one has administrative access to your source control system!
Unit testing is great when done right, and it’s even good when done in a lax manner. However, it’s better to have no unit tests than terrible unit tests.
I hate unit testing done poorly.
Chris originally wrote this article to be tongue-in-cheek, but then he realized he had created a composite of many wonderful experiences. With well over a decade in software development, you are bound to see some things.