Bowling Game Kata Part Two - The Gutterball Game

Let's write our first test. In this test we score a game where every throw was a zero (gutterball).

Gutterball Game

BowlingGame.Test/GameTest.cs
using NUnit.Framework;

namespace BowlingGame.Test
{
    [TestFixture]
    public class GameTest
    {
        [Test]
        public void Game_AllZeros_ReturnsScore()
        {
            var game = new Game();
        }
    }
}

At this point we cannot even run the test because the compiler is returning an error. We need to add a Game class. Put your cursor on Game and press CTRL+. to access the Generate from Usage menu. Select "Generate new type…".

Control Dot on Game

In the Generate New Type dialog, select the BowlingGame project and click Ok.

Generate New Type

Three things just happened.

  1. The Game class was added to the BowlingGame project.
  2. A reference to the BowlingGame project was added to the BowlingGame.Test project.
  3. "using BowlingGame;" was added to the top of the GameTest class. This using statement is not needed. You can remove it.

The next step is to roll 20 zeros.

BowlingGame.Test/GameTest.cs
using NUnit.Framework;

namespace BowlingGame.Test
{
    [TestFixture]
    public class GameTest
    {
        [Test]
        public void Game_AllZeros_ReturnsScore()
        {
            var game = new Game();

            for (int i = 0; i < 20; i++)
            {
                game.Roll(0);
            }
        }
    }
}

The Roll method does not exist, so we cannot compile. Once again we put our cursor over the offending code, press CTRL+. and hope that Visual Studio will help us out.

Control Dot on Roll

We only see one option, "Generate method stub for 'Roll' in 'BowlingGame.Game'".

Press enter and the compiler error goes away.

The BowlingGame compiles, let's run the test.

If you have a Visual Studio productivity tool like Resharper you can run NUnit tests right inside of Visual Studio.

If you are using the Express Edition, or you don't have something like Resharper, you have to run the tests through the NUnit test runner. You can get the test runner through NuGet.

Manage NuGet Packages…

Search for NUnit.Runners. Install it. The test runner is now located in the packages folder of the BowlingGame solution. For example:
~\BowlingGame\packages\NUnit.Runners.2.6.1\tools\nunit.exe

Running the tests results in the following error:

1 test failed "System.NotImplementedException"

We need to get the test passing with as little code as possible. This helps us take small, incremental steps and keeps our code always working.

Let's take a look at what Visual Studio generated for us.

BowlingGame/Game.cs
using System;

namespace BowlingGame
{
    public class Game
    {
        public void Roll(int p)
        {
            throw new NotImplementedException();
        }
    }
}

Well, that explains our "NotImplementedException".

So, what is it going to take to get this test passing? It's tempting to go ahead and code the scoring ability. Doing that would require more code than what would be needed to get the test to pass.

Let's take a look at Uncle Bob's Transformation Priority Premise. The first transformation we should try is "nil". Can we get the test to pass by doing nothing?

BowlingGame/Game.cs
namespace BowlingGame
{
    public class Game
    {
        public void Roll(int p)
        {
        }
    }
}

We remove the exception and the unused using statement from the code and run the test again.

1 test passed

Now that we have a passing test, we can refactor. This is the Red, Green, Refactor pattern from Kent Beck's book, Test Driven Design By Example.

BowlingGame/Game.cs
namespace BowlingGame
{
    public class Game
    {
        public void Roll(int pins)
        {
        }
    }
}

In this case we changed the parameter from "p" to "pins". This is an innocent change, but it is a good habit to run the tests after refactoring.

1 test passed

Now we can continue with the gutterball test.

BowlingGame.Test/GameTest.cs
using NUnit.Framework;

namespace BowlingGame.Test
{
    [TestFixture]
    public class GameTest
    {
        [Test]
        public void Game_AllZeros_ReturnsScore()
        {
            var game = new Game();

            for (int i = 0; i < 20; i++)
            {
                game.Roll(0);
            }

            Assert.AreEqual(0,
            game.Score());
        }
    }
}

We made our first assertion. We assert that we expect zero to be the returned value of scoring the game. The score method does not exist. To get the code to compile we put our cursor on Score and press CTRL+. and generate the Score method.

We see the option, "Generate method stub for 'Score' in 'BowlingGame.Game'". Selecting this option will create the Score function.

If we compile and run the tests, we see our old friend:

1 test failed "System.NotImplementedException"

This time we know why. Let's take a look at the Score function. I'm calling it a function because it's going to return something.

BowlingGame/Game.cs
namespace BowlingGame
{
    public class Game
    {
        public void Roll(int pins)
        {
        }

        public object Score()
        {
            throw new System.NotImplementedException();
        }
    }
}

Unfortunately doing "nil" will not work this time. So, let's see what's next on Uncle Bob's Transformation Priority Premise. It's "constant". Can we return a constant to get the test to pass? Yes, we can return a zero.

BowlingGame/Game.cs
namespace BowlingGame
{
    public class Game
    {
        public void Roll(int pins)
        {
        }

        public object Score()
        {
            return 0;
        }
    }
}

Recompile and run the test.

1 test passed

Let's do a little refactoring before we close out the gutterball test. I'm going to return an "int" instead of an "object".

Our end result for this test looks like:

BowlingGame/Game.cs
namespace BowlingGame
{
    public class Game
    {
        public void Roll(int pins)
        {
        }

        public int Score()
        {
            return 0;
        }
    }
}
BowlingGame.Test/GameTest.cs
using NUnit.Framework;
            
namespace BowlingGame.Test
{
    [TestFixture]
    public class GameTest
    {
        [Test]
        public void Game_AllZeros_ReturnsScore()
        {
            var game = new Game();

            for (int i = 0; i < 20; i++)
            {
                game.Roll(0);
            }

            Assert.AreEqual(0,
            game.Score());
        }
    }
}