Finally I’ve tried the story telling approach to writing blog posts before and it was fun and well-received. So here is a story on outside-in development with SpecFlow and ASP.NET MVC. (Disclaimer – I will not go in to details on web automation or ASP.NET MVC).
Getting the story straightMarcus entered the office with extra spring in his step. New project and he would finally get around to try out the outside-in development style in a real project. It sounded great – but could it really work? He went straight to Tobias, the project manager:
“I’m ready! Where is the specifications?” – he sounded eager… almost to much maybe
”Well, calm down…. For now we have a small side-mission for you. We need you to extract the tasks at hand from our database. It will be a simple application but it will be great to start learning the new work approach” – Tobias did his best to deliver the quite disheartening news to his eager developer.
“OK… I’ll do it” – Marcus was still eager but not as much
”Great! We simply want a list of all the features in our database that isn’t done yet. And there is a service that will deliver them to you. I’ve written the first feature already” – Tobias tried to ride the wave of enthusiasm. He showed Marcus the feature:
To know which features that are up next“OK, but what about the done ones? No one ever want to see them?” – Marcus asked.
As a developer in the team
I want to see a list of all features that isn’t done
“By George! You’re right! We might need to tweak that story a little…. Hmmm how about:”
In order to see a list of the features of our application and their status“That isn’t very clear…” – Marcus said plainly. “Could you talk me through a scenario?”
As a developer in the team
I want to see a list of the features, sorted on their different status
”That’s EXACTLY what we will do now”
They talked for a while and came up with this scenario:
When I navigate to the homepage“We might need to add a scenario for when I show the features that are done also. How about this?”
Then I should see a list of features are not done yet
Given I am on the homepage“That looks alright by me. Now go code! You can get hold of the service to get the items, from Thomas who created it yesterday” – Tobias sent Marcus off to get on with more important stuff.
When I click the radio button for “Show done features”
Then I should see a list of features that are done
Setting up the featureMarcus fired up his Visual Studio. Oh the new 2010 already felt like home, he couldn’t even remember the 2008 version.
The first order of business is to create the solution. Marcus created a blank solution called “Marcusoft.OutsideIn.FeatureDemo”. He then added a class library for his Specification. Executable specifications! It still sent shivers down his spine.
The class library was called Marcusoft.OutsideIn.FeatureDemo.Specs and has references to TechTalk.SpecFlow.dll and the nunit.framework.dll. And of course deleted Class1.cs. “Why is that always created?” – he thought as he hit the delete-button. Hard!
Also Marcus put these reference in a lib-folder, in the top solution-folder. “That’s always a good think”, he thought, “then everybody will get the correct version”. Now Marcus created two folders in the Spec-project; Features and Steps. The Features will contain the Gherkin-features and the Steps-folder the step definitions.
Now the feature could be added. Marcus added a SpecFlow-feature to the Features-folder. He called the feature “BrowseHomePage.feature” and added the following content:
Yeah! That looked good. “Let’s run that and see where it leads us” – he said to himself and ran the tests.
It failed! Or actually it was inconclusive. Which was no big surprise to him, although he couldn’t help but to feel that there was a lot of work ahead.
Keep in step all the timeThe exception from SpecFlow was very informative and helpful. It even gave him some code to get started with. This is what it looked like:
“Sooo… I need to create some steps” – Marcus promptly copied the WhenINavigateToTheHomepage-method and added a new class “HomePageSteps.cs” to the Steps folder. He then pasted the code into the class and ran the test again.
But he was very disappointed to see the same failure… “Aaaah the class of course need to be public… And apparently need that Binding-attribute on top. Lets add that.” He did so and ran again.
“Yup – that was better” – he paused. “Kinda… I don’t do what the step definition says…I’m supposed to navigate to the home-page. But I haven’t got a site yet. So that is my task at hand now.”
“I’ll use Watin to automate the browser” – Marcus said and downloaded and referenced Watin.Core.dll and Interop.SHDocVw.dll.
“And now all I have to do is to navigate to the page in question. Hmmm – I know how to navigate with Watin… but where to… I start off by ripping part of Steven Sanderssons blog post to get a working infrastructure going.” With that Marcus created the following web browser class:
“Great” – Marcus thought to himself “ with this in place I can change the app.config file to point to the root of my application.” He added an app.config that contained some settings and a RootUrl-key.
Marcus went on to add navigation in the When-step like this:
And with that in place Marcus ran the tests again. A browser flashed before his eyes… It was an Internet Explorer but he couldn’t see the content. Also when he checked the test run results he could see that they were still inconclusive. But this time the When-step had passed:
Creating the webMarcus added a new ASP.NET MVC 2 project to his solution; Marcusoft.OutsideIn.FeatureDemo.Web. He started by removing all the membership stuff. That wasn’t needed in this project.
Marcus then picked up the url from the project properties web-tab. The url pointed to http://localhost:49323 which was confirmed when I started the application and got the well-known default page for an ASP.NET MVC site:
He stored that setting in the project, by setting the Specific Port radio button on the Web-properties for the ASP.NET MVC project. He then added that url to the RootUrl-key in app.config of the Specs-project.
Marcus ran the tests again. The same behavior… The browser flashed and he could see anything. In order to see it work Marcus commented the [AfterScenario] in the WebBrowser-class. Now the browser stayed open and Marcus could see the same page being showed. On the same url even.
With a smile on this face he thought: “Progress” and went on to copy the method for the Then step definition.
Then! Why not now?Marcus added the then step he copied from the test result, to the HomePageSteps and ran the tests again. The test are still pending but not with a missing step:
Should-library for assertions:
Let’s write an application
Now some code was needed in the web application. Marcus needed to get the page working and listing the features… which in turn meant that he had to pull the features from the service that Thomas had made.
“Let’s start with the controller. I need to make sure that I can get hold of the data from the service through the controller to the views". Let’s write some tests for it” – Marcus said to himself. He added a test project, referenced nunit.framework.dll, the excellent NSubsiture.dll and the FeatureDBWrapper that he had got before. The FeatureDBWrapper exposed a simple interface like this:
With TDD Marcus started fleshed out the structure of the HomeController and it’s index-method. Still amazed on how well this process works he found himself:
- Creating some fake data with NSubsitute
- Passing the IFeatureDBWrapper substitute into the HomeController, which in turn (and with the help of Resharper in a few keystrokes) made the HomeController take an IFeatureDBWrapper as parameter
- Verify that the right method was called and returned the faked data
Better check with the specifications“Alright – that worked out just fine! Let just run the Specs to be sure…” – Marcus thought and hit Run for the tests. They failed. But not in a good way.
“Actually that is quite strange when I think of it” - Marcus thought. “Because that injected FeatureDBWrapper to the HomeController should have broken the site.” He tried to run it in the browser. And yes – it’s broken. It fails with “No parameterless constructor found for this object”. Just as Marcus suspected.
“But (!) the When-step of my Spec ran just fine. I better add a check that I have arrived on the right page to that step” – Marcus thought. Here is the extension:
Alright – not on to fix the injection problem. I’ll go with Ninject for this. He added Ninject and the following code to his Global.asax.cs:
“Back to the specs” – Marcus said out loud. He ran them and they failed but this time as he expected. On Assertion when not finding the “FeatureStatus: Done”.
“Yeah, that’s right! Haven’t created a view yet”
View – you want to see something?Marcus muttered to himself… “I am no designer…Pixel shufflers… where are they when you need them?” And he created this rather ugly view:
that looked like this when rendered in the browser:
Marcus looked at his watch. Not even lunch yet… “Maybe I’ll start writing the second scenario now. It will probably be faster” – he dived in.
ConclusionAnd with that we leave Marcus and the fantasy world he is in.
In this, very long blog post, I wanted to try out to be driven by the specifications outside in to working code. It felt very natural and had a nice “where do we go now… HERE”-feeling to it. I hope that you could follow along.
You can download the code here.
If you liked this post ... here's more for you:
Published byon Last updated