Jon Kruger -
  • About Me
  • Blog
  • Resume
  • Values
  • Presentations
About Me
Blog
Resume
Values
Presentations
  • About Me
  • Blog
  • Resume
  • Values
  • Presentations
Jon Kruger
.NET, Rhino Mocks, TDD, unit testing

How to use Rhino Mocks – documented through tests

I wanted to come up with a way to show people how to use Rhino Mocks (other than telling them to read the documentation). What better way to do this than by showing you how it works through a bunch of simple unit tests that document how Rhino Mocks works?

So that’s what I did. You can view the code here, or if you want to download the whole project and run the tests, you can get the whole thing here.

(If you’re interested in Moq, how it compares to Rhino Mocks, and to see Moq documented through tests, check out Steve Horn’s post.)

UPDATE: Fixed the test that was incorrectly showing how to use Expect() and VerifyAllExpectations(). Thanks to Sharon for pointing this out.

March 12, 2010by Jon Kruger
TDD

A response to the SWE101 attendees who tried to solve the TDD problem without TDD

This weekend we did some live TDD at the Software Engineering 101 event and broadcast it over LiveMeeting, which was a lot of fun. However, some people have posted solutions (here and here – see first comment) on how they solved the Greed scoring problem without using TDD.

I think you missed the point. The point was to help you learn the TDD thought process and how to put TDD into practice. There are lots of benefits to TDD, and I’ll use these non-TDD examples to illustrate.

How do you know your code works?

Those of you who solved the problem without TDD probably did some sort of manual testing in order to prove that your code is working. You could probably do that with a simple example like the one we had (there were only a few scoring rules). But what happens as we add rules (and in real life we’re always adding rules) and you have to manually test 16 rules? For the record, I took the solution posted here and ran my tests against it.

failing test

Tests are documentation

Tests document what the code is supposed to do. Since we wrote our test methods as sentences that read like English, you can figure out the rules just from reading our tests (as you can see in the image above). This is not documentation in Word format which becomes stale, this is living, breathing executable documentation of what the code is supposed to do.

Readability is important

I feel that the solution that we ended up with was very readable. Here is our implementation code:


public class GreedScorer
{
    public double Score(params Die[] dice)
    {
        var score = 0;

        score += ScoreASetOfThreeOnes(dice);
        score += ScoreASetOfThreeTwos(dice);
        score += ScoreASetOfThreeThrees(dice);
        score += ScoreASetOfThreeFours(dice);
        score += ScoreASetOfThreeFives(dice);
        score += ScoreASetOfThreeSixes(dice);
        score += ScoreEachOneThatIsNotAPartOfASetOfThree(dice);
        score += ScoreEachFiveThatIsNotAPartOfASetOfThree(dice);
        return score;
    }

    private int ScoreASetOfThreeOnes(Die[] dice)
    {
        if (dice.Count(die => die.Value == 1) >= 3)
            return 1000;
        return 0;
    }

    private int ScoreASetOfThreeTwos(Die[] dice)
    {
        if (dice.Count(die => die.Value == 2) >= 3)
            return 200;
        return 0;
    }

    private int ScoreASetOfThreeThrees(Die[] dice)
    {
        if (dice.Count(die => die.Value == 3) >= 3)
            return 300;
        return 0;
    }

    private int ScoreASetOfThreeFours(Die[] dice)
    {
        if (dice.Count(die => die.Value == 4) >= 3)
            return 400;
        return 0;
    }

    private int ScoreASetOfThreeFives(Die[] dice)
    {
        if (dice.Count(die => die.Value == 5) >= 3)
            return 500;
        return 0;
    }

    private int ScoreASetOfThreeSixes(Die[] dice)
    {
        if (dice.Count(die => die.Value == 6) >= 3)
            return 600;
        return 0;
    }

    private int ScoreEachOneThatIsNotAPartOfASetOfThree(Die[] dice)
    {
        if (dice.Count(die => die.Value == 1) < 3)
            return (dice.Count(die => die.Value == 1) * 100);
        if (dice.Count(die => die.Value == 1) > 3)
            return ((dice.Count(die => die.Value == 1) - 3) * 100);

        return 0;
    }

    private int ScoreEachFiveThatIsNotAPartOfASetOfThree(Die[] dice)
    {
        if (dice.Count(die => die.Value == 5) < 3)
            return (dice.Count(die => die.Value == 5) * 50);
        if (dice.Count(die => die.Value == 5) > 3)
            return ((dice.Count(die => die.Value == 5) - 3) * 50);

        return 0;
    }
}

Look how readable our code is. Read the score method. Notice how it tells you exactly what it’s doing. Contrast that with one of the other solutions:


static int Score(int[] numbers)
{
    int valueToReturn = 0;

    for (int numberIndex = 0; numberIndex < numbers.Length; numberIndex++)
    {
        switch (numbers[numberIndex])
        {
            case 1:
                if (
                    (numberIndex + 1 < numbers.Length && numbers[numberIndex + 1] == 1) &&
                    (numberIndex + 2 < numbers.Length && numbers[numberIndex + 2] == 1)
                   )
                {
                    valueToReturn += 1000;
                    numberIndex += 2;
                }
                else
                {
                    valueToReturn += 100;
                }
                break;

            case 5:
                if (
                    (numberIndex + 1 < numbers.Length && numbers[numberIndex + 1] == 5) &&
                    (numberIndex + 2 < numbers.Length && numbers[numberIndex + 2] == 5)
                   )
                {
                    valueToReturn += 500;
                    numberIndex += 2;
                }
                else
                {
                    valueToReturn += 50;
                }
                break;

            default:
                if (
                    (numberIndex + 1 < numbers.Length && numbers[numberIndex + 1] == numbers[numberIndex]) &&
                    (numberIndex + 2 < numbers.Length && numbers[numberIndex + 2] == numbers[numberIndex])
                   )
                {
                    valueToReturn += 100 * numbers[numberIndex];
                    numberIndex += 2;
                }
                break;

        }
    }

    return valueToReturn;
}

To me, this code is not very readable. If you had to implement a new rule in this method, it would be hard to do (plus you have no tests to tell you that you broke an existing rule).

The point of this exercise was not to find a clever way to solve a brain teaser. If you want to do a brain teaser, try and write code that will output a Fibonacci sequence using one LINQ expression. That's the kind of geek stuff that you might do at night for fun. But when you're writing real code, we care about things like readability and maintainability. When you're writing implementation code, use common language and write methods whose names tell you what they do.

TDD leads to well-designed code

As we were writing our first test, our test told us that we needed some class that would score the Greed game. So we named it GreedScorer, which does exactly what the name intends. This class will most likely end up following the single responsibility principle because we gave it a very specific name.

But you guys took so long!

We weren't trying to finish as fast as possible. We were not doing a coding competition. We were practicing and learning the TDD mindset and trying to explain things as we went. As you get better at TDD, it becomes more natural and you learn tricks that help you go faster (for example, sometimes writing a whole bunch of tests, watching them all fail, then making them all go pass is faster than just writing one test at a time and making them pass one at a time).

The bottom line is that we came out with some good, readable, maintainable code (with props to Sirena who helped write it). We were able to prove that our code is working. We don't have any code that we don't need. We could easily respond to change and implementing new scoring rules would be pretty easy. Implementing the Score method was fairly easy because we were building it incrementally (solving lots of little problems is easier than trying to solve a big problem all at once). This is why we do TDD!

March 2, 2010by Jon Kruger
TDD

Code from Software Engineering 101 TDD session + more practice

Thanks to everyone who tuned in to watch our live TDD session. Here is the completed code that we ended up with. If you want to try it for yourself, you can get the rules for the Greed game here.

Here are some other “kata” exercises that you can use to help with your TDD practice. These are other simple examples similar to the Greed game.

String Calculator
Bowling scoring
Tennis scoring

Happy testing!

February 27, 2010by Jon Kruger
Quality, TDD, unit testing

The automated testing triangle

Recently I had the privilege of hearing Uncle Bob Martin talk at the Columbus Ruby Brigade. Among the many nuggets of wisdom that I learned that night, my favorite part was the Automated Testing Triangle. I don’t know if Uncle Bob made this up or if he got it from somewhere else, but it goes something like this.

The Automated Testing TriangleAt the bottom of the triangle we have unit tests. These tests are testing code, individual methods in classes, really small pieces of functionality. We mock out dependencies in these tests so that we can test individual methods in isolation. These tests are written using testing frameworks like NUnit and use mocking frameworks like Rhino Mocks. Writing these kinds of tests will help us prove that our code is working and it will help us design our code. They will ensure that we only write enough code to make our tests pass. Unit tests are the foundation of a maintainable codebase.

But there will be situations where unit tests don’t do enough for us because we will need to test multiple parts of the system working together. This means that we need to write integration tests — tests that test the integration between different parts of the system. The most common type of integration test is a test that interacts with the database. These tests tend to be slower and are more brittle, but they serve a purpose by testing things that we can’t test with unit tests.

Everything we’ve discussed so far will test technical behavior, but doesn’t necessarily test functional business specifications. At some point we might want to write tests that read like our technical specs so that we can show that our code is doing what the business wants it to do. This is when we write acceptance tests. These tests are written using tools like Cucumber, Fitnesse, StoryTeller, and NBehave. These tests are usually written in plain text sentences that a business analyst could write, like this:

As a user
When I enter a valid username and password and click Submit
Then I should be logged in

At this point, we’re are no longer just testing technical aspects of our system, we are testing that our system meets the functional specifications provided by the business.

By now we should be able to prove that our individual pieces of code are working, that everything works together, and that it does what the business wants it to do — and all of it is automated. Now comes the manual testing. This is for all of the random stuff — checking to make sure that the page looks right, that fancy AJAX stuff works, that the app is fast enough. This is where you try to break the app, hack it, put weird values in, etc.

The un-automated testing triangleI find that the testing triangle on most projects tends to look more like this triangle. There are some automated integration tests, but these tests don’t use mocking frameworks to isolate dependencies, so they are slow and brittle, which makes them less valuable. An enormous amount of manpower is spent on manual testing.

Lots of projects are run this way, and many of them are successful. So what’s the big deal? Becuase what really matters is the total cost of ownership of an application over the entire lifetime of the application. Most applications need to be changed quite often, so there is much value in doing things that will allow the application be changed easily and quickly.

Many people get hung up on things like, “I don’t have time to write tests!” This is a short term view of things. Sometimes we have deadlines that cannot be moved, so I’m not denying this reality. But realize that you are making a short term decision that will have long term effects.

If you’ve ever worked on a project that had loads of manual testing, then you can at least imagine how nice it would be to have automated tests that would test a majority of your application by clicking a button. You could deploy to production quite often because regression testing would take drastically less time.

I’m still trying to figure out how to achieve this goal. I totally buy into Uncle Bob’s testing triangle, but it requires a big shift in the way we staff teams. For example, it would really help if QA people knew how to use automated testing tools (which may require basic coding skills). Or maybe we have developers writing more automated tests (beyond the unit tests that they usually write). Either way, the benefits of automated testing are tremendous and will save loads of time and money over the life of an application.

February 8, 2010by Jon Kruger
TDD

Announcing TDD Boot Camp – comprehensive test-driven development training in .NET

If any of you have tried to learn test-driven development, you’ve probably discovered that it is not easy to learn. It’s not something where you can just go read a book or find a few good blog posts and start doing it tomorrow. You have to learn to how to write tests first, how to use testing frameworks, how to write testable code, how to do dependency injection, how to use mocking frameworks, and on and on.

People have asked me for advice on how to learn TDD and I really haven’t had a good answer for them. I’ve tried doing lunch and learn sessions on TDD and other people have done half-day sessions on TDD. All of these are good, but there’s no way that you can cover all of the subjects that you would need to understand in order to do TDD on real world projects in such a short amount of time. Sure, there’s definitely value in these sessions, but when I did my lunch and learn session on TDD, I felt like people went away feeling more confused about all of the stuff that they just realized that they didn’t understand.

Which is why I’m developing the TDD Boot Camp, a comprehensive, three day training course that will cover everything that you need to know in order to do TDD on real world .NET projects. It will be very hands-on with a lot of coding exercises that will help you understand all of the hows and whys of test driven development in .NET. My goal is to teach all of the concepts, tools, and techniques that you need to know to do TDD so that, with some practice, you will effectively be able to do TDD (and hopefully teach others how to do it too!).

I’m working on scheduling some events, so keep an eye on the website as I get things set up. I can also come out to your site if that would work better. Hopefully this will fill in the TDD learning gap so that more people can start realizing the benefits of test driven development.

February 2, 2010by Jon Kruger
TDD

The business value of test-driven development

Most businesses are creating software for one primary reason — to make money. In order to make money, we need software that meets the needs of the business and can be developed and maintained in a reasonable amount of time with a high level of quality. Test-driven development is a discipline that will help you achieve these goals.

Test-driven development involves writing automated unit tests to prove that code is working. The test code is written before the implementation code is written. By writing the tests first, you will know when the code is working once the tests pass. Test names are written as sentences in plain English so that the tests describe what the code is supposed to do. Over time, you will end up with a large suite of automated tests which you can run in a short amount of time. These tests will prove to you that your code is working and will continue to work as you modify or refactor the code base.

Most software applications are intended to be used for many years, and throughout most of their existence, someone will be changing them. The total cost of ownership of an application goes far beyond the cost of the initial effort to create the initial version of the software. The first release is the easy part — you can build the application from the ground up, you don’t have many hindrances, and developers feel very productive. But as time goes on, productivity tends to decrease due to complexity, developer turnover, poor software design, and any number of other reasons. This is where software development really becomes expensive. So much focus is placed on the original cost of building an application without considering how the original development effort will affect the cost of maintaining that application over several years.

Test-driven development can reduce the total cost of ownership of an application. New developers on the team will be able to change the code without fear of breaking something important. The application will have fewer defects (and far fewer major defects), reducing the need for manual QA testing. Your code will be self-documenting because the tests will describe the intended behavior of the code. All of this leads to flexible, maintainable software that can be changed in less time with higher quality.

Software is intended to deliver business value, and test-driven development will help you write higher quality, more maintainable software that can be changed at the fast pace of the business. Test-driven development will lead to successful software projects and enable you to write software that will withstand the test of time.

January 25, 2010by Jon Kruger
TDD

Make TDD your meal ticket in 2010

It’s almost the time of the year where people start making new year’s resolutions and setting goals for the upcoming year. Allow me to propose something for your list: make TDD your meal ticket in 2010.

Why do I say this? Because TDD has revolutionized the way I develop software and has helped me write flexible and maintainable software with fewer defects and is a less stressful way to get things done. I can’t imagine ever going back to writing code without tests, and as a result it’s really difficult to work with developers who don’t write tests because they will write code that is hard to test, which means I won’t be able to write tests either.

In today’s economy, it’s important to differentiate yourself from the crowd if you’re looking for a job, hoping to get a raise, trying to get a promotion, etc. TDD can be that thing that differentiates you from everyone else out there. When I worked at Quick Solutions, we were always looking for developers who practice TDD, but developers with any amount of TDD experience are very hard to find.

December 21, 2009by Jon Kruger
TDD, unit testing

The cost of unit testing

One question that I hear from people who are new to TDD or writing tests is, “How much longer is my feature going to take if I write tests?” This is a valid question. We all have deadlines, so if we have to add something extra to our development process, it better be worth it.

I don’t think I could say it better than this post did, so I’ll just let you read it for yourself.

October 5, 2009by Jon Kruger
Agile, TDD, unit testing

Software development is a series of translations

A lot happens from the time that a business owner envisions an idea in their mind and the time that the idea becomes software. The trick is getting through the whole software development process without losing the original idea.

Have you ever played that party game when you go around the circle whispering the same phrase and when you get to the end the phrase is completely different than when it started? Software development ends up like that a lot (especially when the business owner is changing the original idea!).

The problem is that we all speak a different languages. Developers speak one language, BAs another, PMs another, DBAs another, users another, business people another, executives another, and so on. So a large part of our job is learning how to translate what these people want into developer language (code), and doing it so that, in the end, the software speaks to them in their language.

Here’s a simple example:

Executive: “When we hire new employees, we need to make sure that they have a computer ready for them when they start.”

Business analyst: “User will enter the number of new employees on the screen. The system will check the inventory and make sure that we have enough machines, monitors, keyboards, and mice for the new employees. Each employee should have two monitors.”

Now it’s our turn. As developers, we have to do several translations in the process of writing the software. The DBA (or you) may have to design the database schema. You (the developer) have to write the code.

Remember, the goal is to not lose the original idea. That means that each time we “translate” the original idea, we need to do it little bits at a time.

Usually business analysts don’t give you specs that are written exactly how you want them. This is not a knock on BAs, but they speak a different language than us developers. What we really want from them is a set of acceptance criteria. In other words, we need to know what we have to do in order to complete the feature. Not only that, we need to know how we are going to test our feature so that we know that it’s working.

So let’s take the business analyst’s specs and translate them into acceptance criteria:

Given a stash of unused hardware
   When a user enters the number of new employees
      Then it should verify that we have one machine for each new employee
      Then it should verify that we have two monitors for each new employee
      Then it should verify that we have one keyboard for each new employee
      Then it should verify that we have one mouse for each new employee

   When we don’t have enough machines for new employees
      Then we need to order new machines so that we have one for each new employee

   When we don’t have enough monitors for new employees
      Then we need to order new monitors so that we have two for each new employee

   When we don’t have enough keyboards for new employees
      Then we need to order new keyboards so that we have one for each new employee

   When we don’t have enough mice for new employees
      Then we need to order new mice so that we have one for each new employee

We’re not saying anything drastically different from what the business analyst said. But the way that we wrote it is important. Notice the use of the words given, when, then. Here’s the next translation:


public class Given_a_stash_of_unused_hardware
{
}

public class When_a_user_enters_the_number_of_new_employees 
    : Given_a_stash_of_unused_hardware
{
    [Test]
    public void Then_it_should_verify_that_we_have_one_machine_for_each_new_employee() 
    {
    }

    [Test]
    public void Then_it_should_verify_that_we_have_two_monitors_for_each_new_employee() 
    {
    }

    [Test]
    public void Then_it_should_verify_that_we_have_one_keyboard_for_each_new_employee() 
    {
    }

    [Test]
    public void Then_it_should_verify_that_we_have_one_mouse_for_each_new_employee() 
    {
    }
}

public class When_we_don't_have_enough_machines_for_new_employees 
    : Given_a_stash_of_unused_hardware
{
    [Test]
    public void Then_we_need_to_order_new_machines_so_that_we_have_one_for_each_new_employee() 
    {
    }
}

public class When_we_don't_have_enough_monitors_for_new_employees 
    : Given_a_stash_of_unused_hardware
{
    [Test]
    public void Then_we_need_to_order_new_monitors_so_that_we_have_two_for_each_new_employee() 
    {
    }
}

public class When_we_don't_have_enough_keyboards_for_new_employees 
    : Given_a_stash_of_unused_hardware
{
    [Test]
    public void Then_we_need_to_order_new_keyboards_so_that_we_have_one_for_each_new_employee() 
    {
    }
}

public class When_we_don't_have_enough_mice_for_new_employees 
    : Given_a_stash_of_unused_hardware
{
    [Test]
    public void Then_we_need_to_order_new_mice_so_that_we_have_one_for_each_new_employee() 
    {
    }
}

This is how you do behavior driven development. We took our acceptance criteria and wrote them out as code in the form of unit tests. These unit tests will prove that our code is working (when we get to that point) and it will also act as our documentation of what the code is supposed to do.

The reason that this is important is that we’re still in the middle of doing our translation. A lot of people take the tech specs and immediately start writing implementation code. But by doing that, you skip a step in the translation, and when you do that, you risk losing some of the original intent of the feature. This is one of the reason why writing tests before you write implementation code is important. First of all, if you write your tests first, then when they’re passing, you know that you’re done. Second, you’ve written out what the feature is supposed to do — nothing more, nothing less. This is going to help us implement the feature without losing the original intent of the person who thought it up.

Now, yes now, you can go write the implementation code. By focusing on what the end product should be and since you wrote your tests first, this part should be easy. It’s much easier to achieve your goal when you know what the goal is!

October 2, 2009by Jon Kruger
Design, TDD, unit testing

Software Engineering 101 Conference – Sept. 23

In case you haven’t heard, the Software Engineering 101 Conference is going on in Columbus on September 23. This is a one-day event where you will learn about software design topics and techniques such as object-oriented programming and the SOLID software design principles as well as a super-special hands-on test driven development session! This is all good stuff that every developer should know and it will be well worth your time. Rather than recount all the details, I’ll let you read more on Jim’s blog.

This is a FREE event, so all you have to do is ask your employer if you can go, they don’t even have to pay anything for it. I feel like I say this a lot, but these skills are essential for any software developer and have revolutionized the way that I write code.

Registration is limited, and I expect that it will fill up relatively soon, so don’t wait! You can click here to register.

August 24, 2009by Jon Kruger
Page 3 of 5« First...«2345»

About Me

I am a technical leader and software developer in Columbus, OH, currently working as a Director of Engineering at Upstart. Find out more here...

I am a technical leader and software developer in Columbus, OH, currently working as a Senior Engineering Manager at Upstart. Find out more here...