Tutorial – BDD and Dependency Injection in .Net (2)

In this post we concentrate on separating concerns. We will not cover dependency injection within this post, but we will set things up so that we can cover that topic in the future.

We continue where part 1 left off. The SpecFlow feature file looks as follows:

PlayRoundFeature.feature

Feature: Play a single round of Rock Paper Scissors
	As a player
	I want to play a round
	So that I can test my luck

Scenario: Computer chooses Rock and the player chooses Paper
	Given the computer makes a secret choice of Rock
	When I choose Paper
	Then the result should be "Player Wins!"

Scenario: Computer chooses Rock and the player chooses Scissors
	Given the computer makes a secret choice of Rock
	When I choose Scissors
	Then the result should be "Computer Wins!"

The step definition file has the following:

PlayRoundSteps.cs

namespace RockPaperScissorsTest.Specs.Steps
{
    [Binding]
    public class PlayRoundSteps
    {
        private const string GameKey = "Game";

        [Given(@"the computer makes a secret choice of rock")]
        public void GivenTheComputerMakesASecretChoiceOfRock()
        {
            var game = new Game();
            ScenarioContext.Current.Add(GameKey, game);
        }

        [When(@"I choose paper")]
        public void WhenIChoosePaper()
        {
            var game = ScenarioContext.Current.Get(GameKey);
            game.PlayerMove = "Paper";
        }

        [When(@"I choose scissors")]
        public void WhenIChooseScissors()
        {
            var game = ScenarioContext.Current.Get(GameKey);
            game.PlayerMove = "Scissors";
        }

        [Then(@"the result should be ""Player Wins!""")]
        public void ThenTheResultShouldBePlayerWins()
        {
            var game = ScenarioContext.Current.Get(GameKey);
            Assert.AreEqual("Player Wins!", game.Result());
        }

        [Then(@"the result should be ""Computer Wins!""")]
        public void ThenTheResultShouldBeComputerWins()
        {
            var game = ScenarioContext.Current.Get(GameKey);
            Assert.AreEqual("Computer Wins!", game.Result());
        }

    }
}

The unit tests look as follows:

GameTest.cs


        [TestMethod]
        public void ComputerRock_PlayerPaper_PlayerWins()
        {
            var game = new Game();
            game.PlayerMove = "Paper";
            Assert.AreEqual("Player Wins!", game.Result());
        }

        [TestMethod]
        public void ComputerRock_PlayerScissors_ComputerWins()
        {
            var game = new Game();
            game.PlayerMove = "Scissors";
            Assert.AreEqual("Computer Wins!", game.Result());
        }

With the implementation being as follows:

Game.cs

namespace RockPaperScissors
{
    public class Game
    {
        private string _playerMove;
        public string PlayerMove
        {
            private get
            {
                if (String.IsNullOrEmpty(_playerMove))
                    throw new ArgumentNullException("PlayerMove");
                return _playerMove;
            }
            set
            {
                _playerMove = value;
            }
        }

        public string Result()
        {
            return PlayerMove == "Paper" ? "Player Wins!" : "Computer Wins!";
        }
    }
}

Turning a critical eye onto the Game.cs class we see that it has become responsible for deciding the result of the game as well as the string being returned to the user interface. This class is mixing domain logic with UI concerns. Therefore there are two reasons we may need to change this class. This breaks the single responsibility design principle.

We introduce two enums to help separate concerns. We add the following class to the RockPaperScissors library:

Enums.cs

namespace RockPaperScissors
{
    public enum GameResult
    {
        ComputerWins,
        PlayerWins,
        Draw
    }

    public enum Move
    {
        Rock,
        Paper,
        Scissors
    }
}

Now we would like to remove the domain logic from the Game class and place it into a new Decision Engine class. As always we begin with tests. Add the following unit test in the Tests folder:

DescissionEngineTest.cs

        [TestMethod]
        public void ComputerRock_PlayerPaper_ComputerWins()
        {
            var engine = new DescissionEngine();
            GameResult gameResult = engine.Result(Move.Rock, Move.Paper);
            Assert.AreEqual(GameResult.ComputerWins, gameResult);
        }

This corresponds to the first feature and unit test written in part one. We would like to move the domain code but first we move the tests. We make it pass by implementing the DescissionEngine class in the RockPaperScissors library:

DescissionEngine.cs

namespace RockPaperScissors
{
    public class DescissionEngine
    {
        public GameResult Result(Move rock, Move paper)
        {
            return GameResult.ComputerWins;
        }
    }
}

Then we do the same for the second test:

DescissionEngineTest.cs

        [TestMethod]
        public void ComputerRock_PlayerPaper_ComputerWins()
        {
            var engine = new DescissionEngine();
            GameResult gameResult = engine.Result(Move.Rock, Move.Paper);
            Assert.AreEqual(GameResult.PlayerWins, gameResult);
        }

        [TestMethod]
        public void ComputerRock_PlayerScissors_ComputerWins()
        {
            var engine = new DescissionEngine();
            GameResult gameResult = engine.Result(Move.Rock, Move.Scissors);
            Assert.AreEqual(GameResult.ComputerWins, gameResult);
        }

We make this test pass with the following code:

DescissionEngine.cs

namespace RockPaperScissors
{
    public class DescissionEngine
    {
        public GameResult Result(Move computerMove, Move playerMove)
        {
            return playerMove == Move.Paper ? GameResult.PlayerWins : GameResult.ComputerWins;
        }
    }
}

The DescissionEngine class is now handling the same cases as the Game class. We can now work towards integrating the classes.

The simplest way of doing this is by modifying the result method in Game.cs

Game.cs

namespace RockPaperScissors
{
    public class Game
    {

        private string _playerMove;
        public string PlayerMove
        {
            private get
            {
                if (String.IsNullOrEmpty(_playerMove))
                    throw new ArgumentNullException("PlayerMove");
                return _playerMove;
            }
            set
            {
                _playerMove = value;
            }
        }

        public string Result()
        {
            var engine = new DescissionEngine();
            var gameResult = engine.Result(Move.Rock, (Move) Enum.Parse(typeof (Move), PlayerMove));
            return gameResult == GameResult.PlayerWins ? "Player Wins!" : "Computer Wins!";
        }

    }
}

Run all tests to make sure everything still works…

Now the DescissionEngine decides the result of the game. The Game class decides which UI string to use based on the result of the game. The Game class will only need to worry about three cases e.g. computer wins, player wins and draw. The DescissionEngine can be fleshed out separately to handle all the rules of the game.

At the moment the Game class is tightly coupled to the DecisionEngine. This is the result of instantiating the DecisionEngine within the Game class. This means we would have to edit the Game class should we ever want to use an alternate ‘decision engine’. We can break up this tightly coupled code by using dependency injection, specifically constructor injection. In addition to this flexibility, using dependency injection will allow us to use mocks to test smaller units of functionality. I will cover this in upcoming posts.

Please leave questions and comments below, I will try to get the next post out shortly…

5 thoughts on “Tutorial – BDD and Dependency Injection in .Net (2)

  1. You can easily create reusable objects through encapsulation. However, even the most cohesive, well-encapsulated objects can be tightly coupled with other well-encapsulated objects. Tight coupling results in a tangled web of dependencies composed of objects that are fragile, difficult to reuse, and difficult to unit test. Applications with loosely coupled components, on the other hand, are modular, flexible, and easily tested with unit tests. Dependency injection, the topic I examine in this article, is a simple pattern to loosely couple objects and their dependencies.

  2. Pingback: Tutorial – BDD and Dependency Injection in .Net (3) | The Ramblings of Daryn Holmes

Leave a Reply

Your email address will not be published. Required fields are marked *