An Example of Test-Driven Development

GSoC: Implementing DataFrame in Pharo

May 24, 2017 · 4 min read

In my previous post I have designed the public interface for the DataFrame project in Pharo. Now I will write some tests for making sure that the DataFrame class supports (understands) that interface.

The Ideas Behind TDD

TDD is a radical process that promotes the notion of writing test cases that then dictate or drive the further development of a class or piece of code. This is often referred to as “writing tests first” (Craig Murphy).

It is known that the cost of making changes to the project tends to grow with time. The more changes we make the harder it becomes to introduce new changes. The downside of testing the project after all the vital parts were already implemented is that the bugs revealed by these test would take too much time to be fixed. It is even possible that the logic behind the system’s architecture was affected by these bugs, and fixing them would require us to redesign the whole project.

“Cost of Change” curve with the waterfall model. Image taken from http://www.methodsandtools.com/archive/archive.php?id=20

By “writing tests first” we create the failing tests (“red” or “yellow”) based on what we want to achieve and how we want our system to behave, and then, during the development phase we make them “green” one by one. Then we can add new tests, make them “green” and so on. This way bugs get spotted and eliminated on the earliest stage.

Development Process

The steps described here are not some common practice. That is just something I do in my project. Something that can be seemingly good but horribly wrong.

Step 1: Initial Requirements

The initial project requirements were declared by me in my proposal. I am also planning to create some better documentation with a clear roadmap and project specifications.

I’ve started developing this project by designing the public interface and writing tests for it, before the actual behavior got implemented. This way I make sure that the interface does not reveal any information about the internal architecture of the project.

Step 2: Writing Tests for the Interface

The first test case called DataFrameInterfaceTests contains tests that make sure that objects of the DataFrame class understand the methods we want them to understand. These tests don’t check if the methods are implemented or if they do what they are supposed to. The only requirement is that these methods exist. This can be achieved by testing if a method call raises a MessageNotUnderstood exception. For example, the following test will tell us if the object of DataFrame understands the message columns:

testNameIndexColumns    self shouldnt: [ 
DataFrame new columns: #('Name' 'Allegiances').
] raise: MessageNotUnderstood.

At this point we don’t have any methods in our DataFrame, that’s why all the interface tests fail (they are yellow, which means that the tested condition was not satisfied.

Step 3: Making them Green

Now let’s make these tests green by adding all the methods we want to implement to the DataFrame without actually implementing them.

row: nameIndex

"I need to be implemented"

You can see that all the interface tests are now passing. Even though all these methods are empty, the MessageNotUnderstood exception is not being raised, which means that the assertion is satisfied and the tests are green.

Now we have a DataFrame class with an interface that was designed by us on a previous stage. If any of these methods will be renamed or removed, the tests have to be changed accordingly. This makes the potential changes of the interface more explicit.

Step 4: Behavior Testing and Implementation

At this stage the project can be uploaded to the master branch on GitHub (https://github.com/PolyMathOrg/DataFrame). Now we can fork multiple branches from master and provide different versions of a DataFrame by implementing these methods. Each branch will have a set of test cases testing the behavior of a DataFrame — whether or not the methods work as they are supposed to.

Oleksandr Zaitsev

Written by

PhD Student at Inria Lille, RMoD team. Researcher of software evolution at Arolla. Pharo contributor and GSoC org from Pharo Consortium. MSc. in Data Science.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade