Designing Software that’s Easy To Test

As programmers, we desire to create well crafted software that delights our customers.   Because we care about the long term maintainability of our code, we aspire to craft our code well.    In the ideal case, future programmers should find it easy to change our code while avoiding errors and regressions.  How do we accomplish this vision?

I wanted to share one of my favorite agile software engineering techniques: test first design.  (TFD)  In a classical model of software development, special attention for testing comes at the end of the project.    In agile culture, we aspire to test our software early and often throughout the project.   “Test first design” encourages programmers to write test cases for software units (“classes”) continuously through the life of the project.    For large software applications and games, it becomes more important to keep our software loosely coupled and easy to test.   Think about the components of your software as Lego blocks.   In the ideal case, the various components of your application should be designed to connect together.   At the same time, we should have the ability to test the behavior of each class or “lego block” in isolation.  Does each block function well?   If we snap all the blocks together, does the system behave as expected?

Software as lego blocks

In the following JavaScript code sample, I have presented a qunit test case to help introduce the idea of “test first design.”    The “MathUtil” class has a method for calculating the distance between two points.  In the “arrange” section of the code, we construct the variables and objects of the test case.    After we execute the method under test, we assert that the method “GetDistanceBetweenPoints” returned the correct answer.


test( "MathUtil__GetDistanceBetweenPoints__Success", function() {
//arrange
var util = new MathUtil();
var x1 = 0;
var y1 = 0;
var x2 = 5;
var y2 = 5;

//act
var result = util.GetDistanceBetweenPoints(x1,y1,x2,y2)

//assert
ok( result == 7.0710678118654755 );

});

Unit test frameworks exist in every computer language.   The process for test first design is pretty simple.   Write a test that fails.   After the test case compiles/parses correctly, write just enough code to make the failing test pass.    You are encouraged to write the most simple code that could possibly make the test case pass.     With test cases passing, take a little bit of time to clean up or improve the code.   That’s it!   Repeat the process as much as you like.

TDD cycle

By collecting your test cases over time, you can build a suite of test that will help you discover regressions in the system.    I love that this coding methodology helps you find semantic errors in your code quickly.   What are some other benefits of using “test first design?”   Here are just a few:

  • Find bugs early:  In general, the longer a bug remains in a code base, the more complex and expensive it will be to remove it.    “Test first design” helps you discover and remove defects early.    I don’t want to over sell this methodology.    You still need to use manual, scenario based testing, demo sessions, and peer reviews to detect and remove other classes of defects.  
  • Designing Lego blocks of working software: In test driven development (TDD), we are trying to test each method of a class in isolation.   This pattern of construction encourages us to design our software in baby steps.    The baby steps tend to be loosely coupled.
  • Documentation of behavior: TDD use cases can be used to document most of  the assumptions of a class.   It’s awesome that your test framework can document these assumptions in code and inform you of problems when the test suite is executed.
  • TDD encourages programmers to set and achieve goals:  By crafting a test case before writing production code, you are encouraging lots of good programming behaviors.    By writing a test first, your are more likely to be thoughtful regarding the naming of your methods.   You are more likely to be careful about the data getting passed into the method and how the method will return data.    TDD also encourages you to plan the behavior of the class.
In this post, we have introduced the basics of TDD and test first design.   The following video and e-book from Misko Hevery teaches you advanced concepts and tips for making your software more testable.    Misko is a thoughtful test professional from Google.    This is one of my favorite videos to help introduce TDD.  I hope you enjoy it.

InspiredToEducate.NET Posts