This left me with nothing for unit tests. So I installed the JavaScript tools from Eclipse. That gave me some JS support, but nothing for creating unit tests.
Some googling told me there is such a thing as JsUnit, the JS port of my beloved JUnit. Unfortunately it doesn’t seem to come with Eclipse support, even though this thread indicates it does (or did).
Maybe I’m just doing it wrong. I’d appreciate any hints in the comments.
Now that I’m all set up, it’s time to do a little exercise to get my feet wet. For this I picked the Roman Numerals kata.
I started out by following this JsTestDriver example. I created a new JavaScript project in Eclipse, added src/main/js and src/test/js folders, and created the JsTestDriver configuration file:
Next, I opened the JsTestDriver window using Window|Show View|Other|JavaScript|JsTestDriver and started the JsTestDriver server. I then opened the client in FireFox at http://127.0.0.1:42442/capture.
The next step was to create a new run configuration: Run|Run Configurations|JsTestDriver Test. I selected the project and the JsTestDriver configuration within the project, and checked Run on Every Save.
Now everything is set up to start the TDD cycle. First a test:
RomanNumeralsTest = TestCase("RomanNumeralsTest");
RomanNumeralsTest.prototype.testArabicToRoman
= function() {
var romanNumerals = new TestApp.RomanNumerals();
assertEquals("i", romanNumerals.arabicToRoman(1));
};
The cool thing about JsTestDriver is that it automatically runs all the tests every time you change something. This shortens the feedback cycle and keeps you in the flow. For Java, InfiniTest does the same.
The problem with my current tool chain is that support for renaming is extremely limited. I got Operation unavailable on the current selection. Select a JavaScript project, source folder, resource, or a JavaScript file, or a non-readonly type, var, function, parameter, local variable, or type variable.
Other refactorings do exist, like Extract Local Variable and Extract Method, but they mess up the formatting. They also give errors, but then work when trying again.
All in all I feel satisfied with the first steps I’ve taken on this journey. I’m a little worried about the stability of the tools. I also realize I have a more to learn about JavaScript prototypes.
One of the challenges of maintaining a consistent programming style in a team is for everyone to have the same workspace settings, especially in the area of compiler warnings.
Every time a new member joins the team, an existing member sets up a new environment, or a new version of the compiler comes along, you have to synchronize settings.
My team recently started using Workspace Mechanic, an Eclipse plug-in that allows you to save those settings in an XML file that you put under source control.
The plug-in periodically compares the workspace settings with the contents of that file. It notifies you in case of differences, and allows you to update your environment with a couple of clicks.
Towards a Frictionless Development Environment
Workspace Mechanic is a good example of a lubricant, a tool that lubricates the development process to reduce friction.
My ideal is to take this to the extreme with a Frictionless Development Environment (FDE) in which all software development activities go very smoothly.
Let’s see what we would likely need to make such an FDE a reality.
In this post, I will look at a very small example that uncovers some of the basic components of an FDE.
It would be nicer if the IDE would understand what you’re trying to do and automatically create the skeleton for the class under test for you and save it in the right place.
The crux is for the tool to understand what you are doing, or else it could easily draw the wrong conclusion and create all kinds of artifacts that you don’t want.
This kind of knowledge is highly user and potentially even project specific. It is therefore imperative that the tool collects usage data and uses that to optimize its assistance. We’re likely talking about big data here.
Given the fact that it’s expensive in terms of storage and computing power to collect and analyze these statistics, it makes sense to do this in a cloud environment.
That will also allow for quicker learning of usage patterns when working on different machines, like in the office and at home. More importantly, it allows building on usage patterns of other people.
What this example also shows, is that we’ll need many small, very focused lubricants. This makes it unlikely for one organization to provide all lubricants for an FDE that suits everybody, even for a specific language.
The only practical way of assembling an FDE is through a plug-in architecture for lubricants.
Building an FDE will be a huge effort. To realize it on the short term, we’ll probably need an open source model. No one company could put in the resource required to pull this off in even a couple of years.
The Essential Components of a Frictionless Development Environment
This small example uncovered the following building blocks for a Frictionless Development Environment:
Cloud Computing will provide economies of scale and access from anywhere
Big Data Analytics will discern usage patterns
Recommendation Engines will convert usage patterns into context-aware lubricants
A Plug-in architecture will allow different parties to contribute lubricants and usage analysis tools
An Open Source model will allow many organizations and individuals to collaborate
What do you think?
Do you agree with the proposed components of an FDE? Did I miss something?
Refactorings are standard alterations of the code that change its internal structure without changing its external behavior.
Now, if the Green and Refactor phases are each others opposite, then you might think that there are “opposite refactorings” as well. You would be right.
Robert Martin‘s transformations are standard alterations of the code that change its external behavior without changing its internal structure.
Automated Transformations?
Most of us use powerful IDEs to write our code. These IDEs support refactorings, which means that they can do the code alteration for you in a manner that is guaranteed to be safe.
So do we need something similar for transformations? I think not.
Some transformations are so simple in terms of the changes to code, that it wouldn’t actually save any effort to automate them. I don’t see a lot of room for improving the change from if to while, for instance.
Other transformations simply have an unspecified effect. For example, how would you automate the statement->statements transformation?
The crux is that refactorings keep the external behavior the same, and the tools depend on that to properly implement the refactorings. However, transformations don’t share that property.
Standardized Work
In the Specify/Transform/Refactor view of TDD, we write our programs by alternating between adding tests, applying transformations, and applying refactorings.
In other words, if we look at the evolution of our non-test code through a series of diffs, then each diff shows either a transformation or a refactoring.
This time we’ll take a detailed look at the transformations applied in the Green phase.
The Transformation Priority Premise
Most of you will have heard of the refactorings we apply in the last TDD phase, but there are corresponding standardized code changes in the Green phase as well. Uncle Bob Martin named them transformations.
The Transformation Priority Premise (TPP) claims that these transformations have an inherent order, and that picking transformation that are higher on the list leads to better algorithms.
Anecdotal evidence is provided by the example of sorting, where violating the order leads to bubble sort, while the correct order leads to quicksort.
After some modifications based on posts by other people, Uncle Bob arrived at the following ordered list of transformations:
Transformation
Description
{}–>nil
no code at all->code that employs nil
nil->constant
constant->constant+
a simple constant to a more complex constant
constant->scalar
replacing a constant with a variable or an argument
statement->statements
adding more unconditional statements
unconditional->if
splitting the execution path
scalar->array
array->container
??? this one is never used nor explained
statement->tail-recursion
if->while
statement->recursion
expression->function
replacing an expression with a function or algorithm
variable->assignment
replacing the value of a variable
case
adding a case (or else) to an existing switch or if
Applying the TPP to the Roman Numerals Kata
Reading about something gives only shallow knowledge, so let’s try out the TPP on a small, familiar problem: the Roman Numerals kata.
For those of you who are unfamiliar with it: the objective is to translate numbers into Roman. See the table at the left for an overview of the Roman symbols and their values.
As always in TDD, we start off with the simplest case:
public class RomanNumeralsTest {
@Test
public void arabicToRoman() {
Assert.assertEquals("i", "i", RomanNumerals.arabicToRoman(1));
}
}
We get this to compile with:
public class RomanNumerals {
public static String arabicToRoman(int arabic) {
return null;
}
}
Note that we’ve already applied the first transformation on the list: {}->nil. We apply the second transformation, nil->constant, to get to green:
public class RomanNumerals {
public static String arabicToRoman(int arabic) {
return "i";
}
}
Now we can add our second test:
public class RomanNumeralsTest {
@Test
public void arabicToRoman() {
assertRoman("i", 1);
assertRoman("ii", 2);
}
private void assertRoman(String roman, int arabic) {
Assert.assertEquals(roman, roman,
RomanNumerals.arabicToRoman(arabic));
}
}
The only way to make this test pass, is to introduce some conditional (unconditional->if):
public static String arabicToRoman(int arabic) {
if (arabic == 2) {
return "ii";
}
return "i";
}
However, this leads to duplication between the number 2 and the number of is returned. So let’s try a different sequence of transformations. Warning: I’m going into baby steps mode now.
First, do constant->scalar:
public static String arabicToRoman(int arabic) {
String result = "i";
return result;
}
Next, statement->statements:
public static String arabicToRoman(int arabic) {
StringBuilder result = new StringBuilder();
result.append("i");
return result.toString();
}
Now we can introduce the if without duplication:
public static String arabicToRoman(int arabic) {
StringBuilder result = new StringBuilder();
if (arabic >= 1) {
result.append("i");
}
return result.toString();
}
And then another statement->statements:
public static String arabicToRoman(int arabic) {
StringBuilder result = new StringBuilder();
if (arabic >= 1) {
result.append("i");
arabic -= 1;
}
return result.toString();
}
And finally we do if->while:
public static String arabicToRoman(int arabic) {
StringBuilder result = new StringBuilder();
while (arabic >= 1) {
result.append("i");
arabic -= 1;
}
return result.toString();
}
Our test now passes. And so does the test for 3, by the way.
With our refactoring hat on, we spot some more subtle duplication: between the number 1 and the string i. They both express the same concept (the number 1), but are different versions of it: one Arabic and one Roman.
We should introduce a class to capture this concept:
public class RomanNumerals {
public static String arabicToRoman(int arabic) {
StringBuilder result = new StringBuilder();
RomanNumeral numeral = new RomanNumeral("i", 1);
while (arabic >= numeral.getValue()) {
result.append(numeral.getSymbol());
arabic -= numeral.getValue();
}
return result.toString();
}
}
public class RomanNumeral {
private final String symbol;
private final int value;
public RomanNumeral(String symbol, int value) {
this.symbol = symbol;
this.value = value;
}
public int getValue() {
return value;
}
public String getSymbol() {
return symbol;
}
}
Now it turns out that we have a case of feature envy. We can make that more obvious by extracting out a method:
public static String arabicToRoman(int arabic) {
StringBuilder result = new StringBuilder();
RomanNumeral numeral = new RomanNumeral("i", 1);
arabic = append(arabic, result, numeral);
return result.toString();
}
private static int append(int arabic, StringBuilder builder,
RomanNumeral numeral) {
while (arabic >= numeral.getValue()) {
builder.append(numeral.getSymbol());
arabic -= numeral.getValue();
}
return arabic;
}
Now we can move the append() method to RomanNumeral:
public class RomanNumerals {
public static String arabicToRoman(int arabic) {
StringBuilder result = new StringBuilder();
RomanNumeral numeral = new RomanNumeral("i", 1);
arabic = numeral.append(arabic, result);
return result.toString();
}
}
public class RomanNumeral {
private final String symbol;
private final int value;
public RomanNumeral(String symbol, int value) {
this.symbol = symbol;
this.value = value;
}
public int getValue() {
return value;
}
public String getSymbol() {
return symbol;
}
public int append(int arabic, StringBuilder builder) {
while (arabic >= getValue()) {
builder.append(getSymbol());
arabic -= getValue();
}
return arabic;
}
}
We can further clean up by inlining the getters that are now only used in the RomanNumeral class:
public class RomanNumeral {
private final String symbol;
private final int value;
public RomanNumeral(String symbol, int value) {
this.symbol = symbol;
this.value = value;
}
public int append(int arabic, StringBuilder builder) {
while (arabic >= value) {
builder.append(symbol);
arabic -= value;
}
return arabic;
}
}
There is one other problem with this code: we pass in arabic and builder as two separate parameters, but they are not independent. The former represents the part of the arabic number not yet processed, while the latter represents the part that is processed. So we should introduce another class to capture the shared concept:
public class RomanNumerals {
public static String arabicToRoman(int arabic) {
ArabicToRomanConversion conversion
= new ArabicToRomanConversion(arabic);
RomanNumeral numeral = new RomanNumeral("i", 1);
numeral.append(conversion);
return conversion.getResult();
}
}
public class RomanNumeral {
private final String symbol;
private final int value;
public RomanNumeral(String symbol, int value) {
this.symbol = symbol;
this.value = value;
}
public void append(ArabicToRomanConversion conversion) {
while (conversion.getRemainder() >= value) {
conversion.append(symbol, value);
}
}
}
public class ArabicToRomanConversion {
private int remainder;
private final StringBuilder result;
public ArabicToRomanConversion(int arabic) {
this.remainder = arabic;
this.result = new StringBuilder();
}
public String getResult() {
return result.toString();
}
public int getRemainder() {
return remainder;
}
public void append(String symbol, int value) {
result.append(symbol);
remainder -= value;
}
}
Unfortunately, we now have a slight case feature envy in RomanNumeral. We use conversion twice and our own members three times, so it’s not too bad, but let’s think about this for a moment.
Does it make sense to let the roman numeral know about an conversion process from Arabic to Roman? I think not, so let’s move the code to the proper place:
public class RomanNumerals {
public static String arabicToRoman(int arabic) {
ArabicToRomanConversion conversion
= new ArabicToRomanConversion(arabic);
RomanNumeral numeral = new RomanNumeral("i", 1);
conversion.process(numeral);
return conversion.getResult();
}
}
public class RomanNumeral {
private final String symbol;
private final int value;
public RomanNumeral(String symbol, int value) {
this.symbol = symbol;
this.value = value;
}
public String getSymbol() {
return symbol;
}
public int getValue() {
return value;
}
}
public class ArabicToRomanConversion {
private int remainder;
private final StringBuilder result;
public ArabicToRomanConversion(int arabic) {
this.remainder = arabic;
this.result = new StringBuilder();
}
public String getResult() {
return result.toString();
}
public void process(RomanNumeral numeral) {
while (remainder >= numeral.getValue()) {
append(numeral.getSymbol(), numeral.getValue());
}
}
private void append(String symbol, int value) {
result.append(symbol);
remainder -= value;
}
}
We had to re-introduce the getters for RomanNumeral‘s fields to get this to compile. We could have avoided that rework by introducing the ArabicToRomanConversion class first. Hmm, maybe refactorings have an inherent order too!
OK, on to our next test: 4. We can make that pass with another series of transformations. First, scalar->array:
public static String arabicToRoman(int arabic) {
ArabicToRomanConversion conversion
= new ArabicToRomanConversion(arabic);
RomanNumeral[] numerals = new RomanNumeral[] {
new RomanNumeral("i", 1)
};
conversion.process(numerals[0]);
return conversion.getResult();
}
Next, constant->scalar:
public static String arabicToRoman(int arabic) {
ArabicToRomanConversion conversion
= new ArabicToRomanConversion(arabic);
RomanNumeral[] numerals = new RomanNumeral[] {
new RomanNumeral("i", 1)
};
int index = 0;
conversion.process(numerals[index]);
return conversion.getResult();
}
Now we need an if:
public static String arabicToRoman(int arabic) {
ArabicToRomanConversion conversion
= new ArabicToRomanConversion(arabic);
RomanNumeral[] numerals = new RomanNumeral[] {
new RomanNumeral("i", 1)
};
int index = 0;
if (index < 1) {
conversion.process(numerals[index]);
}
return conversion.getResult();
}
And another constant->scalar:
public static String arabicToRoman(int arabic) {
ArabicToRomanConversion conversion
= new ArabicToRomanConversion(arabic);
RomanNumeral[] numerals = new RomanNumeral[] {
new RomanNumeral("i", 1)
};
int index = 0;
if (index < numerals.length) {
conversion.process(numerals[index]);
}
return conversion.getResult();
}
You can probably see where this is going. Next is statement->statements:
public static String arabicToRoman(int arabic) {
ArabicToRomanConversion conversion
= new ArabicToRomanConversion(arabic);
RomanNumeral[] numerals = new RomanNumeral[] {
new RomanNumeral("i", 1)
};
int index = 0;
if (index < numerals.length) {
conversion.process(numerals[index]);
index++;
}
return conversion.getResult();
}
Then if->while:
public static String arabicToRoman(int arabic) {
ArabicToRomanConversion conversion
= new ArabicToRomanConversion(arabic);
RomanNumeral[] numerals = new RomanNumeral[] {
new RomanNumeral("i", 1)
};
for (RomanNumeral numeral : numerals) {
conversion.process(numeral);
}
return conversion.getResult();
}
And finally constant->constant+:
public static String arabicToRoman(int arabic) {
ArabicToRomanConversion conversion
= new ArabicToRomanConversion(arabic);
RomanNumeral[] numerals = new RomanNumeral[] {
new RomanNumeral("iv", 4),
new RomanNumeral("i", 1)
};
for (RomanNumeral numeral : numerals) {
conversion.process(numeral);
}
return conversion.getResult();
}
Now we have our algorithm complete and all we need to do is add to the numerals array. BTW, this should be a constant:
public class RomanNumerals {
private static final RomanNumeral[] ROMAN_NUMERALS
= new RomanNumeral[] {
new RomanNumeral("iv", 4),
new RomanNumeral("i", 1)
};
public static String arabicToRoman(int arabic) {
ArabicToRomanConversion conversion
= new ArabicToRomanConversion(arabic);
for (RomanNumeral romanNumeral : ROMAN_NUMERALS) {
conversion.process(romanNumeral);
}
return conversion.getResult();
}
}
Also, it looks like we have another case of feature envy here that we could resolve as follows:
public class RomanNumerals {
public static String arabicToRoman(int arabic) {
return new ArabicToRomanConversion(arabic).getResult();
}
}
public class ArabicToRomanConversion {
private static final RomanNumeral[] ROMAN_NUMERALS
= new RomanNumeral[] {
new RomanNumeral("iv", 4),
new RomanNumeral("i", 1)
};
private int remainder;
private final StringBuilder result;
public ArabicToRomanConversion(int arabic) {
this.remainder = arabic;
this.result = new StringBuilder();
}
public String getResult() {
for (RomanNumeral romanNumeral : ROMAN_NUMERALS) {
process(romanNumeral);
}
return result.toString();
}
private void process(RomanNumeral numeral) {
while (remainder >= numeral.getValue()) {
append(numeral.getSymbol(), numeral.getValue());
}
}
private void append(String symbol, int value) {
result.append(symbol);
remainder -= value;
}
}
Retrospective
The first thing I noticed, is that following the TPP led me to discover the basic algorithm a lot quicker than in some of my earlier attempts at this kata.
The next interesting thing is that there seems to be an interplay between transformations and refactorings.
You can either perform a transformation and then clean up with refactorings, or prevent the need to refactor by using only transformations that don’t introduce duplication. Doing the latter is more efficient and also seems to speed up discovery of the required algorithm.
Certainly food for thought. It seems like some more experimentation is in order.
Update: Here is a screencast of a slightly better version of the kata:
There seems to be some confusion between Test-First Programming and Test-Driven Development (TDD).
This post explains that merely writing the tests before the code doesn’t necessarily make it TDD.
Similarities Between Test-First Programming and Test-Driven Development
It’s not hard to see why people would confuse the two, since they have many things in common.
My classification of tests distinguishes six dimensions: who, what, when, where, why, and how.
Test-First programming and Test-Driven Development score the same in five of those six dimensions: they are both automated (how) functional (what) programmer (who) tests at the unit level (where) written before the code (when).
The only difference is in why they are written.
Differences Between Test-First Programming and Test-Driven Development
Test-First Programming mandates that tests be written before the code, so that the code will always be testable. This is more efficient than having to change already written code to make it testable.
Test-First Programming doesn’t say anything about other activities in the development cycle, like requirements analysis and design.
This is a big difference with Test-Driven Development (TDD), since in TDD, the tests drive the design. Let’s take a detailed look at the TDD process of Red/Green/Refactor, to find out exactly how that differs from Test-First Programming.
Red
In the first TDD phase we write a test. Since there is no code yet to make the test pass, this test will fail.
Unit testing frameworks like JUnit will show the result in red to indicate failure.
In both Test-First Programming and Test-Driven Development, we use this phase to record a requirement as a test.
TDD, however, goes a step further: we also explicitly design the client API. Test-First Programming is silent on how and when we should do that.
Green
In the next phase, we write code to make the test pass. Unit testing frameworks show passing tests in green.
In Test-Driven Development, we always write the simplest possible code that makes the test pass. This allows us to keep our options open and evolve the design.
We may evolve our code using simple transformations to increase the complexity of the code enough to satisfy the requirements that are expressed in the tests.
Test-First Programming is silent on what sort of code you write in this phase and how you do it, as long as the test will pass.
Refactor
In the final TDD phase, the code is refactored to improve the design of the implementation.
This phase is completely absent in Test-First Programming.
Summary of Differences
So we’ve uncovered two differences that distinguish Test-First Programming from Test-Driven Development:
Test-Driven Development uses the Red phase to design the client API. Test-First Programming is silent on when and how you arrive at a good client API.
Test-Driven Development splits the coding phase into two compared to Test-First Programming. In the first sub-phase (Green), the focus is on meeting the requirements. In the second sub-phase (Refactor), the focus is on creating a good design.
I think there is a lot of value in the second point. Many developers focus too much on getting the requirements implemented and forget to clean up their code. The result is an accumulation of technical debt that will slow development down over time.
TDD also splits the design activity into two. First we design the external face of the code, i.e. the API. Then we design the internal organization of the code.
This is a useful distinction as well, because the heuristics you would use to tell a good API from a bad one are different from those for good internal design.
Try Before You Buy
All in all I think Test-Driven Development provides sufficient value over Test-First Programming to give it a try.
All new things are hard, however, so be sure to practice TDD before you start applying it in the wild.
One of the important things in a Security Development Lifecycle (SDL) is to feed back information about vulnerabilities to developers.
This post relates that practice to the Agile practice of No Bugs.
The Security Incident Response
Even though we work hard to ship our software without security vulnerabilities, we never succeed 100%.
When an incident is reported (hopefully responsibly), we execute our security response plan. We must be careful to fix the issue without introducing new problems.
Next, we should also look for similar issues to the one reported. It’s not unlikely that there are issues in other parts of the application that are similar to the reported one. We should find and fix those as part of the same security update.
Finally, we should do a root cause analysis to determine why this weakness slipped through the cracks in the first place. Armed with that knowledge, we can adapt our process to make sure that similar issues will not occur in the future.
From Security To Quality
The process outlined above works well for making our software ever more secure.
Some people object to the Zero Defects mentality, claiming that it’s unrealistic.
There is, however, clear evidence of much lower defect rates for Agile development teams. Many Lean implementations also report successes in their quest for Zero Defects.
So there is at least anecdotal evidence that a very significant reduction of defects is possible.
Conferences are a great place to learn new things, but also to meet new people. New people can provide new ways of looking at things, which helps with learning as well.
You can either go to big and broad conferences, like Java One or the RSA conference, or you can attend a smaller, more focused event. Some of these smaller events may not be as well-known, but there are some real gems nonetheless.
Take XML Amsterdam, for example, a small conference here in the Netherlands with excellent international speakers and attendees (even some famous ones).
Attend Workshops
Learning is as much about doing as it is about hearing and watching. Some conferences may have hands-on sessions or labs, but they’re in the minority. So just going to conferences isn’t good enough.
A more practical variant are workshops. They are mostly organized by specific communities, like Java User Groups.
One particularly useful form for developers is the code retreat. Workshops are much more focused than conferences and still provide some of the same networking opportunities.
Get Formal Training
Lots of courses are being offered, many of them conveniently online. One great (and free) example is Cryptography from Coursera.
Some of these course lead to certifications. The world is sharply divided into those who think certifications are a must and those that feel they are evil. I’ll keep my opinion on this subject to myself for once but whatever you do, focus on the learning, not on the piece of paper.
Learn On The Job
There is a lot to be learned during regular work activities as well.
You can organize that a bit better by doing something like job rotation. Good forms of job rotation for developers are collective code ownership and swarming.
There are many ways of testing software. This post uses the five Ws to classify the different types of tests and shows how to use this classification.
Programmer vs Customer (Who)
Tests exist to give confidence that the software works as expected.
But whose expectations are we talking about? Developers have different types of expectations about their code than users have about the application. Each audience deserves its own set of tests to remain confident enough to keep going.
Functionality vs Performance vs Load vs Security (What)
When not specified, it’s assumed that what is being tested is whether the application functions the way it’s supposed to. However, we can also test non-functional aspects of an application, like security.
Before Writing Code vs After (When)
Tests can be written after the code is complete to verify that it works (test-last), or they can be written first to specify how the code should work (test-first). Writing the test first may seem counter-intuitive or unnatural, but there are some advantages:
When you write the tests first, you’ll guarantee that the code you later write will be testable (duh). Anybody who’s written tests for legacy code will surely acknowledge that that’s not a given if you write the code first
Writing the tests first can prevent defects from entering the code and that is more efficient than introducing, finding, and then fixing bugs
Writing the tests first makes it possible for the tests to drive the design. By formulating your test, in code, in a way that looks natural, you design an API that is convenient to use. You can even design the implementation
Unit vs Integration vs System (Where)
Tests can be written at different levels of abstraction. Unit tests test a single unit (e.g. class) in isolation.
Integration tests focus on how the units work together. System tests look at the application as a whole.
As you move up the abstraction level from unit to system, you require fewer tests.
Verification vs Specification vs Design (Why)
There can be different reasons for writing tests. All tests verify that the code works as expected, but some tests can start their lives as specifications of how yet-to-be-written code should work. In the latter situation, the tests can be an important tool for communicating how the application should behave.
We can even go a step further and let the tests also drive how the code should be organized. This is called Test-Driven Design (TDD).
Manual vs Automated Tests (How)
Tests can be performed by a human or by a computer program. Manual testing is most useful in the form of exploratory testing.
When you ship the same application multiple times, like with releases of a product or sprints of an Agile project, you should automate your tests to catch regressions. The amount of software you ship will continue to grow as you add features and your testing effort will do so as well. If you don’t automate your tests, you will eventually run out of time to perform all of them.
Specifying Tests Using the Classification
With the above classifications we can be very specific about our tests. For instance:
Tests in TDD are automated (how) programmer (who) tests that design (why) functionality (what) at the unit or integration level (where) before the code is written (when)
BDD scenarios are automated (how) customer (who) tests that specify (why) functionality (what) at the system level (where) before the code is written (when)
Exploratory tests are manual (how) customer (who) tests that verify (why) functionality (what) at the system level (where) after the code is written (when)
Security tests are automated (how) customer (who) tests that verify (why) security (what) at the system level (where) after the code is written (when)
Sometimes you can select a single alternative along a dimension. For instance, you could perform all your testing manually, or you could use tests exclusively to verify.
For other dimensions, you really need to cover all the options. For instance, you need tests at the unit and integration and system level and you need to test for functionality and performance and security. If you don’t, you are at risk of not knowing that your application is flawed.
Proper risk management, therefore, mandates that you shouldn’t exclusively rely on one type of tests. For instance, TDD is great, but it doesn’t give the customer any confidence. You should carefully select a range of test types to cover all aspects that are relevant for your situation.
Last time, we saw how Behavior-Driven Development (BDD) allows us to work towards a concrete goal in a very focused way.
In this post, we’ll look at how the big BDD and the smaller TDD feedback loops eliminate waste and how you can visualize that waste using code coverage tools like EclEmma to see whether you execute your process well.
The Relation Between BDD and TDD
Depending on your situation, running BDD scenarios may take a lot of time. For instance, you may need to first create a Web Application Archive (WAR), then start a web server, deploy your WAR, and finally run your automated acceptance tests using Selenium.
This is not a convenient feedback cycle to run for every single line of code you write.
So chances are that you’ll write bigger chunks of code. That increases the risk of introducing mistakes, however. Baby steps can mitigate that risk. In this case, that means moving to Test-First programming, preferably Test-Driven Development (TDD).
The link between a BDD scenario and a bunch of unit tests is the top-down test. The top-down test is a translation of the BDD scenario into test code. From there, you descend further down into unit tests using regular TDD.
This translation of BDD scenarios into top-down tests may seem wasteful, but it’s not.
Top-down tests only serve to give the developer a shorter feedback cycle. You should never have to leave your IDE to determine whether you’re done. The waste of the translation is more than made up for by the gains of not having to constantly switch to the larger BDD feedback cycle. By doing a little bit more work, you end up going faster!
If you’re worried about your build time increasing because of these top-down tests, you may even consider removing them after you’ve made them pass, since their risk-reducing job is then done.
Both BDD and TDD Eliminate Waste Using JIT Programming
Both BDD and TDD operate on the idea of Just-In-Time (JIT) coding. JIT is a Lean principle for eliminating waste; in this case of writing unnecessary code.
There are many reasons why you’d want to eliminate unnecessary code:
Since it takes time to write code, writing less code means you’ll be more productive (finish more stories per iteration)
More code means more things a future maintainer must understand, and thus a higher risk of bugs introduced during maintenance due to misunderstandings
Code Coverage Can Visualize Waste
With BDD and TDD in your software development process, you expect less waste. That’s the theory, at least. How do we prove this in practice?
Well, let’s look at the process:
BDD scenarios define the acceptance criteria for the user stories
Those BDD scenarios are translated into top-down tests
Those top-down tests lead to unit tests
Finally, those unit tests lead to production code
The last step is easiest to verify: no code should have been written that wasn’t necessary for making some unit test pass. We can prove that by measuring code coverage while we execute the unit tests. Any code that is not covered is by definition waste.
You can change these colors using Window|Preferences|Java|Code coverage. For instance, you could change Full Coverage to white, so that the normal case doesn’t introduce visual clutter and only the exceptions stand out.
The great thing about EclEmma is that it let’s you measure code coverage without making you change the way you work.
The only difference is that instead of choosing Run As|JUnit Test (or Alt+Shift+X, T), you now choose Coverage As|JUnit test (or Alt+Shift+E, T). To re-run the last coverage, use Ctrl+Shift+F11 (instead of Ctrl+F11 to re-run the last launch).
If your fingers are conditioned to use Alt+Shift+X, T and/or Ctrl+F11, you can always change the key bindings using Window|Preferences|General|Keys.
In my experience, the performance overhead of EclEmma is low enough that you can use it all the time.
EclEmma Helps You Monitor Your Agile Process
The feedback from EclEmma allows you to immediately see any waste in the form of unnecessary code. Since there shouldn’t be any such waste if you do BDD and TDD well, the feedback from EclEmma is really feedback on how well you execute your BDD/TDD process. You can use this feedback to hone your skills and become the best developer you can be.
In essence, BDD is a way to deliver requirements. But not just any requirements, executable ones! With BDD, you write scenarios in a format that can be run against the software to ascertain whether the software behaves as desired.
Given the ATM has $250
And my balance is $200
When I withdraw $150
Then the ATM has $100
And my balance is $50
Given indicates the initial context, When indicates the occurrence of an interesting event, and Then asserts an expected outcome. And may be used to in place of a repeating keyword, to make the scenario more readable.
Given/When/Then is a very powerful idiom, that allows for virtually any requirement to be described. Scenarios in this format are also easily parsed, so that we can automatically run them.
BDD scenarios are great for developers, since they provide quick and unequivocal feedback about whether the story is done. Not only the main success scenario, but also alternate and exception scenarios can be provided, as can abuse cases. The latter requires that the Product Owner not only collaborates with testers and developers, but also with security specialists. The payoff is that it becomes easier to manage security requirements.
Even though BDD is really about the collaborative process and not about tools, I’m going to focus on tools for the remainder of this post. Please keep in mind that tools can never save you, while communication and collaboration can. With that caveat out of the way, let’s get started on implementing BDD with some open source tools.
JBehave
JBehave is a BDD tool for Java. It parses the scenarios from story files, maps them to Java code, runs them via JUnit tests, and generates reports.
Eclipse
JBehave has a plug-in for Eclipse that makes writing stories easier with features such as syntax highlighting/checking, step completion, and navigation to the step implementation.
JUnit
Here’s how we run our stories using JUnit:
@RunWith(AnnotatedEmbedderRunner.class)
@UsingEmbedder(embedder = Embedder.class, generateViewAfterStories = true,
ignoreFailureInStories = true, ignoreFailureInView = false,
verboseFailures = true)
@UsingSteps(instances = { NgisRestSteps.class })
public class StoriesTest extends JUnitStories {
@Override
protected List<String> storyPaths() {
return new StoryFinder().findPaths(
CodeLocations.codeLocationFromClass(getClass()).getFile(),
Arrays.asList(getStoryFilter(storyPaths)), null);
}
private String getStoryFilter(String storyPaths) {
if (storyPaths == null) {
return "*.story";
}
if (storyPaths.endsWith(".story")) {
return storyPaths;
}
return storyPaths + ".story";
}
private List<String> specifiedStoryPaths(String storyPaths) {
List<String> result = new ArrayList<String>();
URI cwd = new File("src/test/resources").toURI();
for (String storyPath : storyPaths.split(File.pathSeparator)) {
File storyFile = new File(storyPath);
if (!storyFile.exists()) {
throw new IllegalArgumentException("Story file not found: "
+ storyPath);
}
result.add(cwd.relativize(storyFile.toURI()).toString());
}
return result;
}
@Override
public Configuration configuration() {
return super.configuration()
.useStoryReporterBuilder(new StoryReporterBuilder()
.withFormats(Format.XML, Format.STATS, Format.CONSOLE)
.withRelativeDirectory("../build/jbehave")
)
.usePendingStepStrategy(new FailingUponPendingStep())
.useFailureStrategy(new SilentlyAbsorbingFailure());
}
}
This uses JUnit 4′s @RunWith annotation to indicate the class that will run the test. The AnnotatedEmbedderRunner is a JUnit Runner that JBehave provides. It looks for the @UsingEmbedder annotation to determine how to run the stories:
generateViewAfterStories instructs JBehave to create a test report after running the stories
ignoreFailureInStories prevents JBehave from throwing an exception when a story fails. This is essential for the integration with Jenkins, as we’ll see below
The @UsingSteps annotation links the steps in the scenarios to Java code. More on that below. You can list more than one class.
Our test class re-uses the JUnitStories class from JBehave that makes it easy to run multiple stories. We only have to implement two methods: storyPaths() and configuration().
The storyPaths() method tells JBehave where to find the stories to run. Our version is a little bit complicated because we want to be able to run tests from both our IDE and from the command line and because we want to be able to run either all stories or a specific sub-set.
We use the system property bdd.stories to indicate which stories to run. This includes support for wildcards. Our naming convention requires that the story file names start with the persona, so we can easily run all stories for a single persona using something like -Dbdd.stories=wanda_*.
The configuration() method tells JBehave how to run stories and report on them. We need output in XML for further processing in Jenkins, as we’ll see below.
One thing of interest is the location of the reports. JBehave supports Maven, which is fine, but they assume that everybody follows Maven conventions, which is really not. The output goes into a directory called target by default, but we can override that by specifying a path relative to the target directory. We use Gradle instead of Maven, and Gradle’s temporary files go into the build directory, not target. More on Gradle below.
Steps
Now we can run our stories, but they will fail. We need to tell JBehave how to map the Given/When/Then steps in the scenarios to Java code. The Steps classes determine what the vocabulary is that can be used in the scenarios. As such, they define a Domain Specific Language (DSL) for acceptance testing our application.
Our application has a RESTful interface, so we wrote a generic REST DSL. However, due to the HATEOAS constraint in REST, a client needs a lot of calls to discover the URIs that it should use. Writing scenarios gets pretty boring and repetitive that way, so we added an application-specific DSL on top of the REST DSL. This allows us to write scenarios in terms the Product Owner understands.
Layering the application-specific steps on top of generic REST steps has some advantages:
It’s easy to implement new application-specific DSL, since they only need to call the REST-specific DSL
The REST-specific DSL can be shared with other projects
Gradle
With the Steps in place, we can run our stories from our favorite IDE. That works great for developers, but can’t be used for Continuous Integration (CI).
Our CI server runs a headless build, so we need to be able to run the BDD scenarios from the command line. We automate our build with Gradle and Gradle can already run JUnit tests. However, our build is a multi-project build. We don’t want to run our BDD scenarios until all projects are built, a distribution is created, and the application is started.
So first off, we disable running tests on the project that contains the BDD stories:
test {
onlyIf { false } // We need a running server
}
Next, we create another task that can be run after we start our application:
task acceptStories(type: Test) {
ignoreFailures = true
doFirst {
// Need 'target' directory on *nix systems to get any output
file('target').mkdirs()
def filter = System.getProperty('bdd.stories')
if (filter == null) {
filter = '*'
}
def stories = sourceSets.test.resources.matching {
it.include filter
}.asPath
systemProperty('bdd.stories', stories)
}
}
Here we see the power of Gradle. We define a new task of type Test, so that it already can run JUnit tests. Next, we configure that task using a little Groovy script.
First, we must make sure the target directory exists. We don’t need or even want it, but without it, JBehave doesn’t work properly on *nix systems. I guess that’s a little Maven-ism
Next, we add support for running a sub-set of the stories, again using the bdd.stories system property. Our story files are located in src/test/resources, so that we can easily get access to them using the standard Gradle testsource set. We then set the system property bdd.stories for the JVM that runs the tests.
Jenkins
So now we can run our BDD scenarios from both our IDE and the command line. The next step is to integrate them into our CI build.
We could just archive the JBehave reports as artifacts, but, to be honest, the reports that JBehave generates aren’t all that great. Fortunately, the JBehave team also maintains a plug-in for the Jenkins CI server. This plug-in requires prior installation of the xUnit plug-in.
After installation of the xUnit and JBehave plug-ins into jenkins, we can configure our Jenkins job to use the JBehave plug-in. First, add an xUnit post-build action. Then, select the JBehave test report.
With this configuration, the output from running JBehave on our BDD stories looks just like that for regular unit tests:
Note that the yellow part in the graph indicates pending steps. Those are used in the BDD scenarios, but have no counterpart in the Java Steps classes. Pending steps are shown in the Skip column in the test results:
Notice how the JBehave Jenkins plug-in translates stories to tests and scenarios to test methods. This makes it easy to spot which scenarios require more work.
Although the JBehave plug-in works quite well, there are two things that could be improved:
The output from the tests is not shown. This makes it hard to figure out why a scenario failed. We therefore also archive the JUnit test report
If you configure ignoreFailureInStories to be false, JBehave throws an exception on a failure, which truncates the XML output. The JBehave Jenkins plug-in can then no longer parse the XML (since it’s not well formed), and fails entirely, leaving you without test results
All in all these are minor inconveniences, and we ‘re very happy with our automated BDD scenarios.
The opinions expressed here are my personal opinions. Content published here is not read or approved in advance by EMC and does not necessarily reflect the views and opinions of EMC nor does it constitute any official communication of EMC.
Error: Twitter did not respond. Please wait a few minutes and refresh this page.
Some of the links contained within this site have my Amazon referral ID, which provides me with a small commission for each sale. Thank you for your support.