| Main |

In this post I will tell you a story about how I used TDD (Test Driven Development) to learn new a new API, and how I successfully managed to accomplish my task before expected, and delivered 100% working code (no defects), even though I did something I’ve never done before – interested? I thought so ;)

In the project I’m currently working on, I was given the task to implement a web service that integrated with a directory service using the LDAP protocol. This was something I’ve never done so far in my career, so I thought it as a fun challenge. The task was simple; I had to implement CRUD (create, read and delete) behaviors to manipulate entries in the directory. My main concern and the obvious show stopper were to figure out how to integrate with the directory service using the LDAP protocol.

As always, before I jump into conclusions, I sat down and started to think about how to solve this task. I had a gut feeling that told me I’ve read about this somewhere, about what’s the best way to learn new API’s. And after while it suddenly came to my mind! – It’s called learning tests.

“Jim Newkirk reported on a project in which Learning Tests were routinely written. When new releases of the package arrived, first the tests were run (and fixed, if necessary.) If the tests didn’t run, there was no sense running the application because it certainly wouldn’t run. Once the tests ran, the application ran every time.” – Kent Beck, Test-Driven development by example

Since I can’t reveal more about my work, I’m going to use another example in this story. I decided it would be fun to learn how to integrate with Twitter using their API’s and C#. Since integrating with Twitter is completely new for me, the situation will be analogues to the one I had solving the LDAP integration task for the customer.

Again, before jumping into conclusion, I started out doing some research, and ended up on Twitter’s APIWiki. The WIKI contained lots of good information and after a few minutes I learned that their API’s is built upon the HTTP protocol and that its REST based. In the WIKI they had listed up 3rd party libraries for several different platforms, and I found a few for .NET, and decided to use an Open Source library called Twitterizer. My rationale for using a library was if the library is good, it would be easier for me to produce working code, and I’ll probably do it faster than using the built-in HTTP libraries in the .NET framework.

If you going to create a Twitter client or another type of application that integrates with Twitter, you probably have to figure out how to;

  • Authenticate and logon to Twitter
  • Update status
  • Get status from friends
  • Get list of followers

Learn to use the library

If you are used to TDD, you start out writing tests before any production code. You are probably also familiar with Uncle Bob’s Three Laws of TDD;

  1. You are not allowed to write any production code unless it is to make a failing unit test pass.
  2. You are not allowed to write any more of a unit test than is sufficient to fail; and compilation failures are failures.
  3. You are not allowed to write any more production code than is sufficient to pass the one failing unit test.

When writing code, I like to work like this, so I started out writing failing tests to document what I had to learn in order to integrate with Twitter. The first, and the obvious test, was to figure out how to authenticate with Twitter. I also added three more failing tests; update status, get friends status and get followers. Here is what I ended up with;

   1: [Test]
   2: public void Authenticate()
   3: {
   4: }
   5:  
   6: [Test]
   7: public void Get_status_from_friends()
   8: {
   9: }
  10:  
  11: [Test]
  12: public void Get_followers()
  13: {
  14: }
  15:  
  16: [Test]
  17: public void Update_status()
  18: {
  19: }

I know, I broke Uncle Bob’s law 2 by writing four tests before any production code, but I’m pragmatic, my goal was to solve my task, not follow the laws like a slave. The positive outcome from breaking law was that I now had decomposed the Twitter integration task, into four more fine granulated tasks. I considered this my to-do list.

The next obvious step was to learn the Twitterizer API, which I did by using the Object Browser in Visual Studio. After fiddling around for a while, I was ready to start solving the first task; how to authenticate a user in order to logon to Twitter. I tested this by login to Twitter, and call the API for receiving status from friends. If the test received status from friends, I could assume the login was successful. After this test passed, the rest was a walk in the park, and here is what I ended up with;

   1: [Test]
   2: public void Authenticate()
   3: {
   4:     Scenario.New("Logon Twitter", scenario =>
   5:     {
   6:         Twitter twitterClient = null;
   7:  
   8:         scenario.Given("user is not logged on");
   9:         
  10:         scenario.When("the user logs on", () =>
  11:             twitterClient = new Twitter(username, password));
  12:  
  13:         scenario.Then("it should be possible to call API", () =>
  14:             twitterClient.Status.FriendsTimeline());
  15:  
  16:     }).Execute();
  17: }
  18:  
  19: [Test]
  20: public void Get_status_from_friends()
  21: {
  22:     Scenario.New("Get status from friends", scenario =>
  23:     {
  24:         TwitterStatusCollection friendsStatus = null;
  25:  
  26:         scenario.Given("the user is logged on", () =>
  27:             twitter = new Twitter(username, password));
  28:  
  29:         scenario.When("friends status is requested", () =>
  30:             friendsStatus = twitter.Status.FriendsTimeline());
  31:  
  32:         scenario.Then("friends status should be received", () =>
  33:             friendsStatus.Count.ShouldNotEqual(0));
  34:  
  35:     }).Execute();
  36: }
  37:  
  38: [Test]
  39: public void Get_followers()
  40: {
  41:     Scenario.New("Get users' followers", scenario =>
  42:     {
  43:         TwitterUserCollection followers = null;
  44:  
  45:         scenario.Given("the user is logged on", () =>
  46:             twitter = new Twitter(username, password));
  47:  
  48:         scenario.When("followers is requested", () =>
  49:             followers = twitter.User.Followers());
  50:  
  51:         scenario.Then("followers information should be received", () =>
  52:             followers.Count.ShouldNotEqual(0));
  53:  
  54:     }).Execute();
  55: }
  56:  
  57: [Test]
  58: public void Update_status()
  59: {
  60:     Scenario.New("Update user status", scenario =>
  61:     {
  62:         scenario.Given("the user is logged on", () =>
  63:             twitter = new Twitter(username, password));
  64:  
  65:         scenario.When("status is updated", () =>
  66:             twitter.Status.Update("hello world..."));
  67:  
  68:         scenario.Then("status should be updated", () =>
  69:             twitter.Status.Show(username).Status.Text.ShouldEqual("hello world..."));
  70:  
  71:     }).Execute();
  72: }

Notice that I’ve used a C# DSL (Domain Specific Language) for describing the tests as scenarios. These scenario driven tests is a well known test pattern called AAA (Arrange, Act, and Assert). I’ve developed the C# DSL and open sourced it – feel free to use it.

The workflow

The workflow is simple. Start out by writing failing tests to document what you need do in order to solve your task. When I started, I had one task, integrate with Twitter, after writing the tests I had decomposed it into four minor tasks. This is a famous problem solving technique called Divide and Conquer. You break down a large, complex problem into smaller, solvable problems. When this is done, you start working on the tests and get them to pass, one by one.

Conclusion

Using TDD to learn new API’s is something everyone should do. If you think about it, it’s exactly what you are doing when you are writing production code and using 3rd party libraries today. You write some code, you compile it, and then run it. If it doesn’t work, you spend some time debugging. And you do this incrementally until you’ve solved the task. If you do it the TDD way, you save yourself from lots of debugging time and you end up documenting how to use the 3rd party library.

There are some other advantages as well. When you hand over the code over to other developers, they can use your learning tests to figure out the same thing you had to figure out, but they can do it by reading your code. Besides that, you also document how a 3rd party library is supposed to work. If they change their API’s or introduce a bug in the next release, your tests will fail, and you can trap this.

Uncle Bob have some good arguments as well;

“If you want to know how to call a certain API, there is a test that does it. If you want to know how to create a certain object, there is a test that does it. Anything you want to know about the existing system, there is a test that demonstrates it. The tests are like little design documents, little coding examples, that describe how the system works and how to use it.” – Uncle Bob

“Have you ever integrated a third party library into your project? You got a big manual full of nice documentation. At the end there was a thin appendix of examples. Which of the two did you read? The examples of course! That's what the unit tests are! They are the most useful part of the documentation. They are the living examples of how to use the code. They are design documents that are hideously detailed, utterly unambiguous, so formal that they execute, and they cannot get out of sync with the production code.” – Uncle Bob

So the next time you have to learn a new API, do it by exercising TDD.

Download the source code

Saturday, May 02, 2009 2:23:16 PM (W. Europe Standard Time, UTC+01:00) 
  Permalink  |  Comments [13]  |  View blog reactions  |