In the last post I completed the start game feature, In this part I am going to be working on the submit guess feature.
Running the first scenario of the submit guess feature throws this error
I create the task SetTheCodeTo, this tells the role to set the secret code to a given value
The details object accessed from the ApplicaitonTask base class contains all the parameters supplied in the scenario step, in this case there is just a single value, so I can use the Value method that returns the first value in the details, if there was more than a single value, they would be defined in the scenario step with keys for example
in this case I would use the Value_Of method of details which requires a key, in the above example the first value has the key “the_number” the second value has the key “from_the_number”.
The role method SetSecretCodeTo after some refactoring simply calls the start game method with the required secret code
The start game method has been changed to accept a secret code which is defaulted to zero using a net 4.0 optional parameter, this value is returned by the mock secret code generator, finally the start method is called which in the game class will call the generator and store its returned value. Running the tests again, I get the following error
The new submit a guess task, gets the guess from the scenario step using the value method, and hands it onto the role submit guess method.
The role submit guess method has to simply call the games guess method and hand in the players guess.
I have already refactored the feature to use the same view screen task
so when I run the acceptance tests I get the expected failure
The error occurs because nothing has been written in the submit guess method, so the screen output collection only includes the lines added during the game start, to get this scenario to pass I added a call to writeline with an empty string in the game guess method.
I now have my first passing test, there is no more code to be written in the acceptance tests, and getting them all to pass now requires the logic to be added to the games guess method, this is going to be more complex than a simple one line change and so I will create a unit test project, and using this finer grain of testing, drive out the required functionality so that all the acceptance tests pass.
The features I have written for my game form the framework within which I write the production code, and where required unit tests. how do I decide when unit tests are required?
If I can’t make the scenario step pass with a simple line of code, either new code or calling an already established method, then unit tests are required, for example I didn’t feel the need to unit test any of the game start code, as this was almost all to do with writing out to the screen, simple calls to WriteLine, however the calls to guess now need some logic to mark the guess against the secret code so I will unit test this, but always with a view to getting the scenario steps to pass, working from the most simple case towards the most complex.
In the future when I look at the unit tests I should be able to see the flow back towards the feature that caused the unit tests existence, using this technique I have found that the tests become more focused, they become the scaffolding within which I am writing my production code, and although there are fewer, they cover the code better and allow for the codebase to expand and change in the future.
Spec Salad has allowed me to avoid the monolithic step definition file which can be difficult to navigate, instead replacing it with a roles and tasks that are directly linkable to the feature text, more focused and easier to navigate in the future.
The project layout for code breaker also shows how the split between features, roles and tasks helps with the reading of the codebase, all the actual doing code is contained within the roles, whilst the tasks are responsible for calling the correct role method with the required parameters.
If this style of behaviour driven design is of interest then I can recommend the RSpec book, although the language used is Ruby the techniques taught are universal.