Disclaimers and introduction
I am now the father of three kids. They are my #1 priority. This project will come second. I’m doing the project for myself mostly, but am very humbled by the fact that several people already have shown interest in my undertakings.
Up to now I’ve also have time to look at the project half-an-hour at the time. With several hours of back-in-my-head-thinking in between. That might be good.
I have no master plan. I will make mistake as you sure will notice in this post... I do not intend to document just the result but also my sidesteps and mistakes. I am a firm believer that it’s true our mistakes that we learn the most.
OK – on with the show.
Step carefully now
Where we left off we got an error message and stub implementation from SpecFlow like this:
Given the following Kanban boards
--- table step argument ---
yada yada yada...
No matching step definition found for the step. Use the following code to create one:
public class StepDefinitions
[Given(@"the following Kanban boards")]
public void GivenTheFollowingKanbanBoards(Table table)
So I created a Steps folder and added the suggested code to a HomeSteps class. I also added the other two step definitions from the suggested coded. I left all of steps pending for now. Here is the code:
My plan is to not go against the GUI this time. Partly because the outside-in experience is a bit clearer when you skip the GUI, but also since I’ve already demonstrated that in another blog post
Specing out the first step
OK – the first steps says that some “Kanbanboards” is needed. So the first order of business is to create them. I’ll use the Assist-namespace of SpecFlow to get help to turn the SpecFlow Table into a list of object. This led me to specify the initial layout of the Domain object KanbanBoard.
Here’s the code (really simple):
And for those wondering I moved the KanbanBoard class into the model directory of the Web project, when I created it below.
But that doesn’t really cut it. We need to stick them somewhere. Later on we want to pull these from a repository right? Right! The background step sets up 4 Kanban boards but in the Then-step only the top 3 favorited should be returned as “Top Kanban boards”. Hmm – so we need to stick a fake database into the repository in order to mock it out.
Here’s my plan; I was thinking on using EF Code First which defines the database context as a class inheriting from DbContext and exposing DbSet’s to write queries against. So maybe that DbContext could be a dependency to the my repository and I can mock it when doing unit tests.
Let’s see if I can get there.
Creating the web project
One of the tools I wanted to try out is MvcScaffolding that looks very interesting. or that to work out properly (I think?) I need an MVC project. So I create an empty one. This is the first need is see for it so in a way I’m forced to create it.
Lets do that!
I simply created a MVC 3 project using the wizard. No unit-tests since I don’t need them. Yet. I went with Razor as my view engine.
Choosing "Internet application” above will give me some initial structure. You win some and you loose some with that. I started by removing the Account model, -controller and -view-stuff since I haven’t seen the need for that yet. I’m planning on using OpenID for authentication later on.
I can now install the MvcScaffolding. Lets get MvcScaffolding (with NuGet of course), when I did that with the Add Library Package Reference dialog I got this error:
And reading the excellent introduction post by Steven Sandersson I understand why. This package is all run from the Package Console. So I’ll install it from there too. Makes sense. The command is simply:
And with the power of NuGet I got the required dependencies pulled down as well:
Successfully added 'EFCodeFirst 0.8' to Web
Successfully added 'T4Scaffolding 0.8.5' to Web
Successfully added 'MvcScaffolding 0.8.7' to Web
Detour – wrong project
Bah! I installed it into the wrong project. There is a tricky little drop down in the package management console that tells you which project to install into.
So I had to learn how to uninstall packages... Simple:
Scaffold me a repository
I’ll now create a model object called KanbanBoard using MvcScaffolding with this command. I had to set the Default Scaffolder first – read Stevens post for that. In order to get this command to fire properly I had to set the default DBContext and the default Repository. Here is the command:
Scaffold Repository KanbanBoard
But now I got an error stating:
Cannot find primary key property for type 'Web.Models.KanbanBoard'. No properties appear to be primary keys.
I suspect a simple ID property will be enough... Let’s add it to the KanbanBoard class. Yup – it worked!
I now have a context created and a repository using that context. Hey – even an interface for the Repository.
I now wrote a test that shows that a Repository cannot be created without a KanbanBoardsDbContext (the name I used for my DBContext-object). Here is the test (in a new Tests-project):
OK – that in turn led me to a lot of refactorings:
- I extracted a interface called IKanbanBoardsDbContext from the KanbanBoardsDbContext class
- I updated the KanbanBoardRepository to be dependent to that interface instead of the concrete implementation.
- I used NuGet like a wizard an installed Should, installed Should Fluent, Uninstalled Should () and finally installing a mocking framework called NSubsitute. Man NuGet makes you work fast fast. Imagine an extension for Visual Studio that grabbed the framework you need when you used methods from it ...
Back to the steps
There – now I can update the Given-step from way back to hold a mocked repository that returns the given kanbanboards. Here is the implementation:
Nice! The background step is now Green and refactored properly. Now we can get on with the next steps.
“When I to to the homepage” in this case translates to “Call the Index action” of the KanbanBoardsController. I’ll then get a view model back, keep it in the ScenarioContext and check that it contains the right stuff in the Then-steps.
Here is the When step definition I wrote:
Aaaand it was around this time that I realized that I was going about this the wrong way.
Step back, breath and reconsider
My aim was to learn the tools, MvcScaffolding among others. So I can now go one of two ways. The way the code is coming about now is backwards in TDD terms since I get the code generated (well scaffolded) for me. For example I would rather have a single method in the repository called GetTopThree or something. Or I can stay with the tools and only use my features to drive me forward. Also, looking at the code in the generated repository class it’s not much to test.
I’ll go with option two; I’ll use the tools I wanted to learn and the code they give me and tweak it to my need.
So now – what does that do with my design? For now I’ll leave it as simple as possible, which in this case is the generated code from MvcScaffolding. I might push the repository down to an application service later on but it will be ok as it is now.
No time to loose – but I’ll leave out the details to save you, dear read, some time.
After some refactorings I now ended up with this Given step definition:
Here is my When step definition:
And the Then step definition:
Let my just add that for the Then-part there is a an excellent table Comparison helper in SpecFlow 1.5 that I would used if not NuGet handed me 1.4 of SpecFlow instead
Finally the Index-method and constructor of the Kanban controller now looks like this.
I am not altogether happy with this session. It was too long and I mostly made mistakes. But I learned to love NuGet and got to try out MvcScaffolding and we are already best friends.
I think that the next step is to set up a simple end to end test for the homepage to get the application fully runnable. Right now we’re lacking a dependency injection framework. But it’s late, I fix that later.