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

Changing how I structure unit tests

When I write unit tests, I use the BDD-style GIven/When/Then format so that the tests are descriptive and explain the business functionality that is being implemented. But I’ve recently changed the way that I do it.

Let’s say that I’m implementing bank account functionality and I am writing code to implement the following:

Given a bank account
When I deposit money into the account
Then the balance should increase by the amount of the deposit

The old way

I used to write them like this:

[TestFixture]
public class When_I_deposit_money_into_the_account : Specification
{
    private Account _account;

    public void Establish_context()
    {
        _account = Given_a_bank_account();
    }

    public void Because_of()
    {
        _account.Deposit(10m);
    }

    [Test]
    public void Then_the_balance_should_increase_by_the_amount_of_the_deposit()
    {
        _account.Balance.ShouldEqual(10m);
    }

    private Account Given_a_bank_account()
    {
        return new Account();
    }
}

This style is used by RSpec and many people in the .NET community. I’ve had a lot of success doing it this way, but I’ve always had some complaints.

  • The Given/When/Then phrases are spread out and aren’t in order.
  • We have the Specification base class, which isn’t bad but I think it might confuse new people who know NUnit but don’t know my special base class.
  • If you have a lot of “given” statements, you’re tempted to use inheritance or nested contexts, each with their own level of setup, virtual properties and methods, etc. This is very unreadable and gets unwieldy very quickly.

The new way

This isn’t really a new way, but it’s new to me. I’ve seen it before over the years but I didn’t really start doing it until I joined my current team where they did it this way and I’ve come to like it a lot better than the old way.

[TestFixture]
public class Bank_account_tests
{
    [Test]
    public void Deposit()
    {
        Given_a_bank_account();
        When_I_deposit_money_into_the_account();
        Then_the_balance_should_increase_by_the_amount_of_the_deposit();
    }

#region Helper methods  

    private void Given_a_bank_account()
    {
        _account = new Account();
    }

    private void When_I_deposit_money_into_the_account()
    {
        _account.Deposit(10m);
    }

    private void Then_the_balance_should_increase_by_the_amount_of_the_deposit()
    {
        _account.Balance.ShouldEqual(10m);
    }

#endregion
}

The best thing about doing it this way is that the business functionality is clearly specified at the top of the class and the Given/When/Then statements aren’t spread out all over the place. There are no crazy inheritance hierarchies, base classes, or big setup methods. When I write tests, I just write out the Given/When/Then scenarios in plain text and then use Specs2Tests to generate the test code for me. Then all I have to do is fill in the private helper methods. This is really easy, like filling in the blanks.

Also, I typically hate regions but in this case I find that they work quite well because they hide the helper methods that I typically don’t want to see when I open the class file.

It depends

Obviously there are situations where this is all overkill and you can just write simple tests without Given/When/Then methods all over the place. Just do whatever makes sense. I’ve found that this new-to-me way leads to very readable and easy to maintain tests.

January 18, 2012by Jon Kruger
Uncategorized

When good enough is (or isn’t) good enough

I came across this post the other day that went on and on railing on things that the author found unacceptable in today’s web frameworks, specifically Rails and ASP.NET MVC. It covered the whole gamut of issues, from abstract base classes in ASP.NET MVC to mega-controllers in MVC frameworks.

I’ve thought a lot of the same things too, to various extents. For example, I’ve never understood why controllers existed. Why can’t we just define routes that are handled by route handler classes that use conventions and REST and things like that? Yet I continue to use controllers in web apps. It made me think, at what point is something bad enough to do something about it and when do I just live with it?

This is the kind of question that makes software development so difficult, but at the same time a lot of fun. Today we were looking at a piece of code that needed to be refactored. We couldn’t figure out what the right way was to implement it, nor could we decide if it was worth the time to even do anything about it.

How do you decide what to do in this situation? The way I see it, you have to look at the return on investment on everything you do. In my controller example, I could invest the time to implement some non-controller solution. On a large enough project, I would probably get a good return on investment compared to using controllers.

But then again, you could argue that since controllers are towards the outer layers of the stack, maybe you can live with it. I care much more about the sanctity of the domain model because that’s the heart of my application. So is it really worth the time or not?

But it gets more complicated than that. Let’s say it takes me a week to implement the non-controller solution. During that time I’m not delivering any client facing features, and that might not sit too well with the people paying for your project. I was in this situation once, and the project almost got cancelled. Thankfully I pulled it out and was on the project for a year and a half and my framework investments more than paid off. But those first few weeks were nerve racking.

So what’s the answer to my original question? I guess it depends. As does pretty much everything else in software development. Which means that you don’t get an easy way out and you are going to have to use your head.

I still think I’m right about the return on investment thing. But at the same time you need to be shrewd about it.

January 16, 2012by Jon Kruger
Agile

The three amigos

Part of being a developer is taking requirements that are written by business analysts and understanding the business problem and the requirements enough to develop a working software solution to solve the problem. In most environments, BAs will work with the developers to help them understand the feature. Once the developers are done, the QA team has to try to understand all of the requirements that the BAs and developers already covered extensively.

You can run into multiple problems here. First, many business analysts write requirements in a format that are not detailed enough to outline all of the edge cases. This is not a knock on business analysts, but they often think in terms of use cases and how the business will use the functionality. But this is why we have a team. Business analysts are better at thinking about the needs of the business and how the app will solve business problems. Developers and testers are good at thinking about the details but sometimes don’t always see the big picture.

This is why it’s so important to bring all of the team members together so that we can take advantage of all of our strengths. We do this in a meeting we call the “three amigos”.

How It Works

A three amigos meeting consists of a business analyst, a QA tester, and a developer. If it’s a larger feature that might involve more than one developer or more than one tester, then you might have more people in the meeting. The BA has written up all of the requirements beforehand, and ideally everyone in the meeting will have read through them before the meeting so that people can have a basic understanding of the feature and can come with their questions.

Once we all have a basic understanding of what we need to develop, we read through the requirements together and someone starts writing all of the test scenarios on a whiteboard. We’re not writing out the complete test plans, we’re just covering the scenarios that need to be tested and maybe some of the things that each scenario will check for. The primary goal is here to figure out what needs to be tested and how we’re going to test each scenario (unit tests, acceptance tests, or manual tests).

Outcomes

The primary outcome of the three amigos are acceptance tests written in Given/When/Then format. Actually writing these out can take a little time, so we don’t do that with everyone sitting in a room. Typically a developer or a tester will work on it outside of the meeting, and once they have the scenarios all written out, then we do a quick review with everyone else that was involved in the original three amigos meeting to make sure that we all agree with what was produced.

Benefits

When you get everyone involved up front, you spread the understanding of what’s being developed across multiple team members. On most teams, BAs and developers have a good understanding of what’s being built, but QA people are left in the dark until you’re most of the way through the process. This way, QA people know what’s going on and they can add their valuable input before a line of code is written. As a developer, this will also help you because the QA people helped you agree on the acceptance criteria that you’ll need in order to complete the feature. No more guessing about what QA is going to test or whether you’ve built everything that needs to be built.

Automating acceptance tests becomes much easier when QA people have helped you come up with the tests and have agreed on them. This is also a good chance to talk to the QA team about what you’re going to automate so that they know that they don’t have to spend as much time manually testing scenarios that the developers have fully automated. Remember, we’re all on the same team, and we’re all responsible for quality. It shouldn’t matter who is testing something as long as it gets tested.

In the end, you end up with fewer bugs because developers know what they need to build and they have everything they need to build it with no coding errors. Certainly this works much better if you’re writing automated unit tests and acceptance tests, but even if you aren’t, at least you will know what you need to build and what it needs to be able to do in order to pass all of the QA tests.

Exceptions

As with everything in software development, it helps to use common sense. We typically don’t do three amigos meetings for really simple features. There’s no hard and fast rule about this, so you have to use your head. If it doesn’t make sense to have a meeting with a bunch of people to review something that you can handle with simple hallway conversations, then go with that.

We don’t always do three amigos on bugs either. If it’s a coding error, there isn’t much to discuss, it just doesn’t work correctly. If we missed something in the requirements, it might require a bigger discussion about the new requirement.

I think that it’s dangerous to make blanket policies that say that you must have a meeting or a certain amount of documentation before you start development on something. The goal is to develop working software that meets the needs of the business with a sufficient level of testing and documentation. You have to decide what that is and how you get there.

January 4, 2012by Jon Kruger
Agile

Just another run of the mill Wednesday

On my current project, we release every 2 weeks. We do the push to production on Saturday, so we set a deadline of Wednesday night for everything to be developed and tested so that we can have two days for demos and UAT.

I remember a certain Wednesday a couple of months ago where things were chaotic to say the least. We looked at the board on Wednesday in the early afternoon and there were 20 items where testing was not complete. We were running around trying to make sure that everything got tested. The entire development team was helping out with testing. Many people stayed past dinnertime to get everything done.

This past Wednesday was much different. Everyone was very relaxed. There was only one item on the board that was still being tested. We were all working on getting stuff ready for the next iteration. And oh by the way, one of the QA testers was out on vacation and another one had been moved to another project.

I immediately thought back to that chaotic Wednesday a few months ago and thought about everything that has happened since then. We certainly had come a long way to get to the point where things were much more relaxed. So what happened?

The Three Amigos

Before development can start on a feature, we have a “three amigos” meeting where developers, business analysts, and QA people get together and decide on the acceptance criteria for the feature. This helps us all get on the same page and make sure that we know what we’re building. It also gets the QA team involved very early in the process, so when it comes time for them to manually test the feature, they already know it inside out.

Automating acceptance tests

The outcome of the three amigos meeting is acceptance criteria. Developers take these and automate them whenever possible (we use a combination of unit tests and acceptance tests using SpecFlow). The development workflow now looks something like this:

  • Work with the QA team to write out the acceptance tests in SpecFlow
  • Develop all of the components needed to make the feature work, writing unit tests along the way
  • Try and get the acceptance tests to pass, fixing any problems we find along the way

When I’m working on the “try and get the acceptance tests to pass” phase, I’m going to find pretty much all of the coding errors that we made during development. The development ticket is still marked as “In Development” at this point, which is very important. We all take quality seriously, both QA testers and developers. I’m not going to hand it over to be tested by the QA team until I can get all of the acceptance tests to pass.

Almost no bugs

Because we knew what we were building up front and because we automated pretty much all of the testing, the QA team is finding very few bugs in the new features that we’re developing. One of our testers brought this up in our retrospective this past week and mentioned how they got everything tested so much faster because they weren’t finding bugs, writing up bugs, waiting for bugs to be fixed, and retesting bug fixes.

We had looked at the schedule earlier in the week and we had thought that developers might have to help out with testing because one of the testers was on vacation and they had some items to test that we thought would take a long time. In the end, no developers had to help with testing and testing got done ahead of schedule!

Everyone talks about how bugs are a waste of time, how they slow you down, etc., but it was really cool to see it play out. Yeah, getting those acceptance tests to pass takes a little extra time, but now I can hand a completed feature over to QA and have a good chance of not having any bugs. We had two developers working for a week on the feature that we completed, and we did it with no bugs. Not only that, we have automated acceptance tests that will do our regression testing for us.

Recap

A lot of the changes that we’ve made seem to be relatively minor, but they’ve produced huge dividends. Much of it comes down to discipline, not cutting corners, communicating effectively, and taking pride in your work. I’m really excited about what we’re going to be able to do from here and I expect to have even more stories to tell in the near future.

January 3, 2012by Jon Kruger

About Me

I am a technical leader and software developer in Columbus, OH. 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...