Skip to content

Instantly share code, notes, and snippets.

@curtismitchell
Created December 5, 2014 21:25
Show Gist options
  • Save curtismitchell/2cb60e10f199f76dc937 to your computer and use it in GitHub Desktop.
Save curtismitchell/2cb60e10f199f76dc937 to your computer and use it in GitHub Desktop.

Testing "Units"

This is a post about unit testing. I will describe some methods of automating unit tests after I have described the process of defining units.

According to Martin Fowler, an author on agile development methodologies, the definition of a "unit" has been vague since the very beginning.

There were definitional concerns about XP's use of unit testing right from the early days. I have a distinct memory of a discussion on a usenet discussion group where us XPers were berated by a testing expert for misusing the term "unit test."

In the same article, Fowler details some differences in what people consider to be a "unit".

Object-oriented design tends to treat a class as the unit, procedural or functional approaches might consider a single function as a unit. But really it's a situational thing - the team decides what makes sense to be a unit for the purposes of their understanding of the system and its testing.

By these definitions, "units" are purely the concern of a developer, or someone that understands classes and functions. Logically speaking, this practice should lead to more maintainable code.

Why unit test?

Are we creating more maintainable code? Or, are we producing a more quality product or system? The primary goal is important and may vary from team-to-team. It is important to understand why we write unit tests. First, let's explore a few benefits of unit testing.

Collective Ownership

Unit testing protects code from being accidentally altered, as described on ExtremeProgramming.org:

Unit tests enable collective ownership. When you create unit tests you guard your functionality from being accidentally harmed. Requiring all code to pass all unit tests before it can be released ensures all functionality always works. Individual code ownership is not required if all classes are guarded by unit tests.

Collective ownership is also a means of protecting against bottlenecks. It prevents a single person from having exclusive ownership of part of a system. And, it allows anyone to contribute enhancements and bug fixes.

Refactoring

Unit tests can confirm when code has been intentionally altered without changing functionality.

Unit tests enable refactoring as well. After each small change the unit tests can verify that a change in structure did not introduce a change in functionality

Continuous Integration

Unit tests enable integration of code into a shared code repository, frequently, while ensuring functionality is still intact.

Building a single universal unit test suite for validation and regression testing enables frequent integration.

Note: Frequently, here, is measured in hours.

Simple design

Practitioners of Test-First or Test-Driven development produce code, only in response to a failing test. This method of development intends to focus on how the code will be used and eliminate unnecessary code.

By creating tests first your design will be influenced by a desire to test everything of value to your customer.

While Test-First development is not a required practice for embracing unit testing, it is worth noting because of the aforementioned benefits.

Testing Features

Given the goals of collective ownership, refactoring, and continuous integration, it seems imperative to test the features of a project.

Features are units

Initially, this may seem controversial or short-sighted without further explanation. Allow me to explain.

Whether we write tests for maintainability or quality, our higher-level goal is to manage the cost of changing our code. We want collective ownership because we do not want bug fixes or features to require a "special developer" in order to get completed. We want the ability to refactor code because we want assurance that a system is stable after we make code more optimal.

Ultimately, we want to deliver value to customers, frequently, with automated quality assurance baked into our process.

Defining features

Features, use a language easily understood by your customers to describe the value we aim to deliver. The audience of your code is a major consideration when determining how to measure the quality of your code.

For example, as a back-end developer, you may be tasked with the development of a component that records and returns Activity Streams for a social application or service. In doing so, you would need to make some determinations about how your audience will interact with your code. Will it be a native library or a web service?

Once you have decided on an approach, it is important to test your code in a way that resembles how your audience will use it. The quality of your code will be determined by the user's experience.

Native libraries should be tested from their public API. If your public API is tested, and the code does not contain non-essential code, the code coverage will be high.

Likewise, web services should be tested from their public entry points as well. In some cases, the application server will process a request before handing it over to your code. The entry into your code is where your unit testing should begin.

XP testing goals

Unit testing is a practice that was heavily advocated by the founders of ExtremeProgramming (XP). The ExtremeProgramming site suggests:

  1. Create automated unit test suites
  2. Test all classes
  3. Use a test-first approach

If code is written with a test-first approach that starts with the public API. And, if the developer writes just-enough code to make the test pass (before refactoring), all of the classes would be tested in the resulting system.

References

UnitTest, Martin Fowler, May 5, 2014 Unit Tests, Don Wells, 1999

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment