On Thursday, March 3rd, the application development group held our latest Code Craft Workshop, focusing on unit testing fundamentals, led by Nick Goede and myself (both from the eMoney emX Select Integrations team).
Our workshops typically begin with a short presentation about the subject we’re covering. In this presentation we described the characteristics of high quality unit tests, talked about refactoring unit tests, how to approach getting existing code under test, and some common challenges and pitfalls that developers face. The material that we covered comes from a variety of sources. A majority of it comes from the experience Nick and I have accumulated unit testing and practicing Test-Driven Development for the last ten years. We also incorporated advice from experts on the topic, including Robert Martin (from his book Clean Code), Justin Searls, Sandi Metz (from her book Practical Object-Oriented Design in Ruby) and Michael Feathers (from his book Working Effectively with Legacy Code).
After the presentation the team usually splits into pairs and begins the interactive portion of the workshop. For this workshop we started with a collection of four C# classes without tests that we asked the pairs to get under unit test. The code was prepared by Nick and I in advance. These example classes are a subset of a fictional system to create and manage a college’s Dean’s List.
Nick and I come from a background of practicing Test-Driven Development (TDD) and have found it to be a fantastic practice that helps us create high quality, changeable code. However, since TDD is a separate topic for our workshops we decided to start with a set of untested classes for this workshop. This gave the developers a chance to practice unit testing existing code which is something that every developer should be comfortable with if they are working in a codebase with spotty unit test coverage.
Encounter Common Unit Testing Challenges
We wanted to create an environment for the team to explore solving issues that are commonly encountered when getting existing code under test. One challenge we addressed was dealing with code that has logic based on the current time. Additionally, we covered getting classes under test that either cannot be instantiated in a test harness themselves or have dependencies that cannot be instantiated in a test harness.
Experience with Learning Tests
Another goal was to give the team an opportunity to practice Learning Test techniques to get an existing codebase under test. These techniques are described in detail in Clean Code to learn how to use a third-party library and in Working Effectively with Legacy Code to get existing code under unit test.
Relationship Between Well Designed Code and Simple Tests
Finally, all of these classes for the workshop were very small. Most only had a single public method. Here we wanted to shine a light on the relationship between well designed object-oriented code (i.e., loosely coupled, highly cohesive, small classes with small methods, adhering to the Single Responsibility Principle) and very simple and clear unit tests.
We ended the workshop with a discussion about the teams’ solutions and any problems they had encountered. Nick and I also presented our unit tests for the classes that we had prepared prior to the workshop.
Up next for us is to watch some talks about unit testing as a group and move on to other workshop topics including Test-Driven Development.