TDD for Beginners pt2 - Pig Latin

by percent20 12/5/2007 4:48:00 PM

Part 1: TDD Test Driven Development for Beginners pt1
Part 2: TDD for Beginners pt2 - Pig Latin
Part 3: TDD for Beginners pt3 - The Application
Part 4: TDD for Beginners pt4 - Unit Tests

I like to do "Real World Coding" and "Real World Contexts" when doing tutorials, if I can. Someone suggested that most people that want to learn and do TDD usually want to start using it with an existing project, and I should go about the series in that way. I liked that idea, but it presented a simple problem of teaching the very basics of TDD. My solution is this part 2. I am going to walk you through doing a _VERY_ basic Pig Latin converter, and how to use TDD to accomplish writing it. Then the rest of the series is going to be how to incorporate tests into an existing project, and a couple parts on adding new features using TDD.

Download NUnit
Before you can do TDD you need to get something to run your tests. I personally use
NUnit, but there are other options available.
Download
( Get the MSI for the latest version using .NET 2.0 Library )
Documentation

Next you need to Install it just run the installer. Just go through the normal next next next process.

How to configure Visual Studio to do Tests
This is pretty straight forward process and is a project by project basis. When you install NUnit it will add several NUnit assemblies to the GAC and when you start a new project that you are going to write tests for (which should be most now), you need to add new refernce, in the solution explorer, and choose NUnit.Framework assembly. Next you add the following line to your using statements.

using NUnit.Framework;

Once that is done you are pretty much set and ready to start writing tests.

Test Driven Development

Now that we have the preliminary stuff out of the way we can start to concentrate on what is important. Learning Test Driven Development. Sorry for the long post you are about to endure.

What we are going to write is a Converter class that allows us to convert words to another language. In the case of our example we are going write a class to be able to convert words to pig-latin (as long as the word doesn't start witha vowel). By writing it as a convter class it will make the code easier to use, implement, test, and extend.

TDD Process
There is a basic process you run through when doing Test Driven Development. I wrote about it in another post, but will re-list it here as it is very important and is the core to TDD.

  1. Write the Test Code
  2. Compile the Test Code (It should fail since you haven't implemented anything yet)
  3. Implement Just enough code to Compile
  4. Run the Test to see it fail
  5. Implement just enough to make it pass
  6. Run test to see it pass
  7. Refactor for clarity and eliminate duplication
  8. Rince and Repeat (repeat from the top)

I am going to walk you through each of these steps and explain them as I go.

Write the Test Code

First we need to create our test class file. So add a class file to a new console project (if you want following along) and name it ConverterFixture. The name means that this is a test file that will be testing the converter class.

Test For Converter Class

The above code is what we refer to as writing the test code first. Lets walk through each line.

[TestFixture]
This is the attribute we set in C# to let NUnit know this class containts tests. It is a Nike thing "Just do it" at the top of your test classes. The class also must be public for NUnit to find and use it.
public class ConvertFixture
This is the name of the class that is going to containt all of our tests for our Converter class.
[Test]
This is the attribute we set in C# to tell NUnit this is an actual test that will be run. All the code in this method below is used to ultimately run a test.
public void ShouldConvertWordToPiglatin()
In order for the method to be a test it needs to be public, void, non-static, and take no parameters. Our method meets all those requirements. The naming might seem odd, but the purpose is so that you can easily understand the purpose of what "should" happen by the end of this test (Look up Behavior Driven Development). This may be obvious by our method test, but when you get into more complex code then tests can become exponentially longer with the purpose being lost. Though nameing is up to you this is what I do.
Converter c = new Converter();
Creates a new instance of the Converter object.
string word = c.ToPigLatin("hello");
From this code we are converting a word "hello" to pig latin using the instance of the converter object from above and assigning to a string object. Or we are converting hello to pig latin.
Assert.AreEqual("ellohay", word);

This is the bread and butter, kind of, of tests. Assertions are how you actually test things in TDD and using Assert object is how you do it in NUnit. There are actually quite a few Assertions you can make, but the one we have here is Assert.AreEqual which compares what the output "Should be" to what it actually is. I suggest when you get this far take a look through intellisense at all that are available to you to use.

Now what we have is a test for our converter object that we haven't made yet.


Compile the Test Code

If you are following along and doing TDD the correct way when you hit compile you will get a big fat ERROR and it won't compile. Congrats that is exactly what it is supposed to do. If it does compile something is wrong.

Implement Just enough code to Compile

At this point we are ready to start writing code for our program. We will write just enough code for our program to compile. The reason behind this is so that you don't write unecessary code and the more code you try to write to pre-implement/pre-solve problems can lead to problems later. Writing just enough code to compile can keep you in check so that you don't write too much code. Here is the code that is just enough to compile the program.

- In this code you can see we created the class Converter.
- Created a method called ToPigLatin() with a return type of string and takes a string parameter.
- It then returns the string s.

Now try to compile. It should compile with 0 errors.

Run the Test to see it fail

Next is to actually run the test. To do that here are the steps I follow from finding and opening NUnit to hitting run. Once you open the assembly in NUnit all you need to do is just hit run from then on after each compile.

  1. Start
  2. All Programs
  3. NUnit 2.4.3
  4. Click NUnit GUI (.NET 2.0)
  5. File
  6. Open Project...
  7. Find assembly (which was in below folder)
  8. Location of Assembly
  9. Select Assembly
  10. Click Open
  11. Click Run

At this point it the test should fail

Test 1 Fails on First Run

 

Implement just enough to make it pass

No we are ready to add the functionality to make that stinking test pass so we can feel good about our code working.

The code above is the code needed to make the test pass. I will run through the code mostly line by line after the declaration of the method.

char[] theArray = s.ToCharArray
Here we are taking the string and spliting up each individual character into an array to so we can manipulate it better.
string final = "";
We are setting the variable final to a nothieng string because are going to run through a loop and add characters to it.
the whole for loop
This is basically going through the array for the word and starting at the second character and assigning it to the variable final. So basically it is taking "hello" and turning it into "ello".
return final + theArray[0] + "ay";
Here we are taking ello adding h to the end and then appending "ay" to it. The final looks like ellohay. We then take that and return it so the test can check if it was done right.

Run test to see it pass

Now you should be able to hit the bug run button in NUnit once you compile the program and get everything all Green.

Feels good doesn't it.

Refactor for clarity and eliminate duplication

In this case we really don't have anything that we need to refactor so we can do the next step.

 
Rince and Repeat
(repeat from the top)

If we had more to do then we start over from the top on the next method/functionality that we want to write. Remember though not to write to much functionality at once.

 

Wrap-up

Now that we have gone through all the steps i'll post up the final code and the code that implements the converter class we just wrote. Then the application that runs it.

ConverterFixture.cs

Converter.cs 

Implementation inside the main method

Program.cs

It actually running

 

Final Thoughts

As you can see Test Driven Development can be very effective in making sure that your code does work. What is great about TDD is that you can spend a while coding on a project and because you have tests later when you do some refactoring to make things prettier and work better you know if and where EVERYTHING is broken. Also TDD allows you to start almost anywhere in your application that you want so if you want to start in the business logic layer, lets say, and not in your data access layer you can because there are ways to test without haveing the Data Access Layer implemented, I will show that too later.

There are a lot of benefits and I can only talk about a couple of the benefits right now so as the series progresses I'll talk about more. In the next part, maybe couple of parts , of the series i'll post up the code for our application that doesn't have tests and do a walk through of all the code.

Please, feel free to download the code I have attached play with it maybe add your own language converter to it with some tests. Please give me any feedback you want good bad or indifferent.  

TDDSeries1PigLatin.zip (7.81 kb)

kick it on DotNetKicks.com

Currently rated 5.0 by 3 people

  • Currently 5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Tags: , , , ,

.NET | TDD | Tutorials

Related posts

Comments

12/5/2007 6:01:55 PM

trackback

Trackback from DotNetKicks.com

TDD pt2 Pig Latin

DotNetKicks.com

12/10/2007 5:18:44 AM

Brent Schooley

It strikes me that you have not written "just enough to make it pass" for your first test. It starts off well when you implement the first version and just "return s;", but your code to make the test pass is more than is needed to make that one test pass. The "just enough to make it pass" for this test would be to replace "return s;" with 'return "ellohay"'. This would make the test itself pass, however when you add another test case to the test (which you should be doing!), that test would fail. Then you would add the logic to make both of those test cases pass. Just my thoughts.

Brent Schooley us

Add comment


(Will show your Gravatar icon)  

  Country flag

[b][/b] - [i][/i] - [u][/u]- [quote][/quote]



Live preview

8/7/2008 1:16:16 PM

Powered by BlogEngine.NET 1.3.0.0
Theme by Mads Kristensen


My Flare

AddThis Feed Button

National Blog Posting Month

Eagle Scout

I'm Test Driven

[Reserved for MVP status I want to earn]

View Buddy Lindsey's profile on LinkedIn

Twitter



Disclaimer

The opinions expressed herein are my own personal opinions and do not represent my employer's view in anyway.

© Copyright 2008

Sign in