This is a continuation of the last blog where we continue to create tests and code for our Tenpin Bowling Scorer class.
Refactoring
If you look at the code below you will notice we are instantiating the Scorer class in each test.
[TestFixture] public class Scorer_NUnit_Tests { [Test] public void ShouldReturnPlayersName() { var _player = "Denham"; var _scorer = new Scorer(_player); Assert.That<string>(_scorer.Player, Is.EqualTo(_player)); } [TestCase(0, 11)] [TestCase(12, 1)] [TestCase(6, 6)] [TestCase(-5, 8)] public void EnterInvalidFrameScores(int Bowl1, int Bowl2) { var _player = "Denham"; var _scorer = new Scorer(_player); Assert.That(() => _scorer.FrameScore(Bowl1, Bowl2), Throws.TypeOf<ArgumentException>()); } [TestCase(0, 0)] [TestCase(0, 10)] [TestCase(10, 0)] [TestCase(5, 5)] public void EnterValidFrameScores(int Bowl1, int Bowl2) { var _player = "Denham"; var _scorer = new Scorer(_player); _scorer.FrameScore(Bowl1, Bowl2); } }
Let’s move that outside to reduce code duplication.
[TestFixture] public class Scorer_NUnit_Tests { string _player = "Denham"; Scorer _scorer = null; [SetUp] public void CallBefore() { _scorer = new Scorer(_player); } [Test] public void ShouldReturnPlayersName() { Assert.That<string>(_scorer.Player, Is.EqualTo(_player)); } [TestCase(0, 11)] [TestCase(12, 1)] [TestCase(6, 6)] [TestCase(-5, 8)] public void EnterInvalidFrameScores(int Bowl1, int Bowl2) { Assert.That(() => _scorer.FrameScore(Bowl1, Bowl2), Throws.TypeOf<ArgumentException>()); } [TestCase(0, 0)] [TestCase(0, 10)] [TestCase(10, 0)] [TestCase(5, 5)] public void EnterValidFrameScores(int Bowl1, int Bowl2) { _scorer.FrameScore(Bowl1, Bowl2); } }
I have created a method with the Setup attribute which will run before every method marked with the Test attribute. This makes the tests a bit cleaner.
Calculating Scores
We have the ability to add frame scores; let’s start writing the code for returning the current score. At this stage we will ignore spares and strikes. First let’s test that the initialised score starts out at Zero.
[Test] public void InitialisedScoreShouldBeZero() { var _currentScore = _scorer.Score; Assert.That(_currentScore, Is.EqualTo(0)); }
This is where some people get tripped up. We can actual write just enough code to get the test to pass. Don’t worry about it at this stage. We will add additional code as we add more tests.
public int Score { get { return 0; } }
Next I am going to add a frame score, check the score, add another frame score, check the score and so forth. This means we will assert multiple times within the same method.
[Test] public void CalculateScoreWithoutSparesOrStrikes() { _scorer.FrameScore(0, 0); Assert.That(_scorer.Score, Is.EqualTo(0)); _scorer.FrameScore(1, 2); Assert.That(_scorer.Score, Is.EqualTo(3)); _scorer.FrameScore(3, 4); Assert.That(_scorer.Score, Is.EqualTo(10)); _scorer.FrameScore(5, 4); Assert.That(_scorer.Score, Is.EqualTo(19)); }
Let’s run the test.
It has failed. Let’s look at the message below.
As you can see, we expected a value of 3 however; 0 was returned. Now we need to edit our Score property to calculate the total score.
public int Score { get { int _currentScore = 0; foreach( var _score in _frameScores) { var _bowl1 = _score.Item1; var _bowl2 = _score.Item2; _currentScore += _bowl1; _currentScore += _bowl2; } return _currentScore; } }
We added just enough code to keep out running totals. Now when we run our tests, they all pass.
In the next blog we will add spares and strikes.