January 31, 2010 by
ryan
Behavior Driven Development is something that has interested me forquite awhile. I have constantly tried to write my tests as clear andconcise as possible but once I saw
Cucumber for Ruby that became thenew standard for what I was trying to achieve in .NET. This is where
SpecFlow comes in.
SpecFlow is a BDD library for .NET that aimsto add testing capabilities that are similar to Cucumber -- that is,specifications are written in human readable Gherkin Format. From theproject site:
SpecFlow aims at bridging the communication gap between domain experts and developers by binding business readable behavior specifications to the underlying implementation.
In theory, I really like that domain experts could write the specifications but I would be interested in seeing how that works out.
So what exactly is this Gherkin format?
According to the Gherkin project on github, 'Gherkin is the language that Cucumber understands. It is a Business Readable, Domain Specific Language that lets you describe software’s behaviour without detailing how that behaviour is implemented.' In other words, its a common DSL for describing the required functionality for a given system.
This functionality is typically broken down by feature and each feature has a number of scenarios. A scenario is made up of 3 steps: GIVEN, WHEN and THEN (which seems to somewhat loosely correspond to Arrange, Act, Assert) and in a simplistic world, looks a little like this:
GIVEN an admin user
WHEN user requests top secret data
THEN return the list of data
If you want to learn more about the Gherkin format check out
Engine Yard's Introduction to BDD with Cucumber by Dave Astels or
Given-When-Then by Aslak HellesøyQuick Synopsis
I've recently started to move my blog over to a new server and a new root domain name; this could have an adverse affect on inbound links. In order to make sure this move was successful, I wanted to write an app to perform 301 redirects from the old URL to the new one.
There are a number of examples out there already for performing 301s but I wanted to make sure I was testing the code -- It seemed like a great opportunity to get a little more use out of SpecFlow.
Initial Setup
- Download and run the SpecFlow installer
- Create a new Project and add a reference to SpecFlow and NUnit Framework
- Add references to your mocking framework (this example is using Moq)
On with the code!
After all the references are sorted out add a SpecFlow feature.

The feature file is where we're going to define our specifications. I want to make sure that when a request is made to the old root it will get redirect to the new root url. So here is what the feature looks like initially:
Feature: Redirection
In order to not upset the google
As a blogger who almost never has the time to blog
I want to redirect my old url to my new one
Scenario: Redirect root request
Given I have entered a request to http://www.frickinsweet.com/ryanlanciaux.com
And the old url is frickinsweet.com/ryanlanciaux.com
And my new url is ryanlanciaux.com
When the request is made
Then the response url is http://www.ryanlanciaux.com
And the response has a 301 in the status
Notice that over in the Solution Explorer window you can expand the feature to reveal a .cs file.

The class is an auto-generated file that updates when the .feature file is changed. We can run this through our test runner to watch it fail and get some extra information as to why it failed.

The tests are failing because there is no real definition to the scenario steps. We can almost directly copy and paste the output from the test runner dialog to a new class and fill in the code for the methods with standard unit testing code. Like I said before, I treat everything that is a GIVEN statement like an arrange section of a standard test; WHEN and THEN like act and assert respectively.
We could hardcode these tests to be specifically run against the urls specified in the scenario but this approach feels brittle and does not encourage code reuse. In order to use these these same steps in our future scenarios we can add wildcard mappings rather than specifying a single url in the attribute definition. The wildcard mapping is the familiar .* surrounded by parenthesis.
24 [Given(@"I have entered a request to (.*)")]
Also note now that when we have a wildcard mapping, we can pass in a parameter to that ScenarioStepDefinition
public void GivenIHaveEnteredARequestToHttpWww_Frickinsweet_ComRyanlanciaux_ComPage2(string url)
The final result is a lot of code but it is broken down into small, reusable sections.
[TestFixture]
[Binding]
public class RedirectTest
{ private string oldUrl;
private string newUrl;
private string requestedUrl;
private string finalUrl;
private RedirectHandler _handler;
private Mock<HttpContextBase> mockContext;
private Mock<HttpResponseBase> mockResponse;
[Given(@"I have entered a request to (.*)")]
public void GivenIHaveEnteredARequestToHttpWww_Frickinsweet_ComRyanlanciaux_ComPage2(string url)
{ var uri = new Uri(url);
requestedUrl = url;
mockContext = new Mock<HttpContextBase>();
mockContext.Setup(x => x.Request.Url).Returns(uri);
}
[Given(@"the old url is (.*)")]
public void GivenTheOldUrlIsFrickinsweet_ComRyanlanciaux_Com(string url)
{ oldUrl = url;
}
[Given(@"my new url is (.*)")]
public void GivenMyNewUrlIsRyanlanciaux_Com(string url)
{ newUrl = url;
//now that we know both old and new url do a replace on httpcontexts' url
//setup what we expect the called url to be and throw a callback on the mock so we can verify later
mockResponse = new Mock<HttpResponseBase>();
mockResponse.SetupProperty(x => x.Status);
mockResponse.Setup(x => x.AddHeader("Location", requestedUrl.Replace(oldUrl, newUrl))) .Callback(() => finalUrl = requestedUrl.Replace(oldUrl, newUrl));
mockContext.Setup(x => x.Response).Returns(mockResponse.Object);
}
[When(@"the request is made")]
public void WhenTheRequestIsMade()
{ _handler = new RedirectHandler();
_handler.ProcessRequest(mockContext.Object, oldUrl, newUrl);
}
[Then(@"the response has a 301 in the status")]
public void ThenTheResponseHasA301InTheStatus()
{ Assert.That(mockContext.Object.Response.Status == "301 Moved Permanently");
}
[Then(@"the response url is (.*)")]
public void ThenTheResponseUrlIsTheNewUrl(string expectedUrl)
{ Assert.AreEqual(expectedUrl, finalUrl);
}
[Then(@"301 is not in the headers")]
public void Then_301IsNotInTheHeaders()
{ Assert.IsNull(mockResponse.Object.Status);
}
}
Since we are using wildcards instead of raw urls in the step definitions we can easily write other tests that will just work with out adding any extra code.
Scenario: Redirect to correct path on new url
Given I have entered a request to http://www.frickinsweet.com/ryanlanciaux.com/page2
And the old url is frickinsweet.com/ryanlanciaux.com
And my new url is ryanlanciaux.com
When the request is made
Then the response url is http://www.ryanlanciaux.com/page2
And the response has a 301 in the status
This project, in its entirety, is hosted on GitHub. Check it out if you are interested in seeing SpecFlow in the context of the whole (tiny) application. Make sure that you add all the files from the lib dir into your references the first time you run it or you will receive all kinds of errors -- additionally, I wrote this quickly for myself so there is no real warranty / guarantee that the code is free from defects -- use at your own risk. :)
Download Project from GitHub
Visit the SpecFlow homepage
Pass it along
August 7, 2009 by
ryan
I know I've been quiet for a little bit here but wanted to point out some great news. Simone Chiaretta and Keyvan Nayyeri's book Beginning ASP.NET MVC 1.0 is available for purchase in the US on Amazon. Both Simone and Keyvan have a wealth of knowledge about the framework, so I'm really looking forward to the book. For more information check out
March 24, 2009 by
ryan
No Controls?
Since the very early ASP.NET MVC previews, the
most common argument I've heard against using the framework is the lack
of user controls. In my opinion, this is a mixed blessing, however, for
some, this is a show stopper. What can you do to provide a rich user
interface with the MVC framework, while not reinventing the wheel?
jQuery
Now
you could go ahead and program a full fledged data grid or WYSIWYG
editor, however, unless you have a bit of time to spare this is not the
ideal solution. As most may realize, jQuery fits very nicely to fill in
the gaps left by the absence of user controls. For the most part, the
controls are not going to let you just drag-and-drop, type in a dataset
and profit but a lot of the pain is kept to a minimum.
Examples
Ingrid

If
you're looking for a data grid there are a number of options available
pictured above is Ingrid. Flexigrid is another good one that people
have used with the MVC framework, however, their site appears to be down at the moment.
Treeviews are available
Radio Buttons / Check Boxes
Check out the jQuery plugin database.
Getting Started
So,
if you've decided you want to look more into using jQuery plugins -- a
couple of tips that may make the transition a little easier:
- Read up on what people using different languages are doing. I'm
not saying that you should necessarily go out and learn Rails or
CakePHP/CodeIgniter (although, it is beneficial). but at least look at the
techniques that programmers from that realm of things are doing -- see how they are implementing their controls.
What tips do you have for creating robust user interfaces with the MVC framework?
January 27, 2009 by
ryan
I had a great time tonight at the Findlay .NET User group! Thanks everyone that battled the weather to come out and hear me talk about the ASP.NET MVC Framework. As promised, I have posted the route constraint to allow only alphabetical values to be accepted as valid input for the display named message.
routes.MapRoute("Message",
"Message/{action}/name/{Name}/",
new { controller = "Message", action = "HelloWorld", name = "" },
new {name="[a-zA-Z]+"}
);
I apologize about the lapse in memory -- The regular expression needed a + at the end to signify that it was more than one character whoops :) For more information on Routes check out
Justin Etheredge's post on routing
January 23, 2009 by
ryan
I will be giving a talk on the ASP.NET MVC Framework at the
Findlay .NET User Group on Tuesday, January 27th (5:30pm - 7:30pm). If you're in NW Ohio and want to learn more about the MVC framework and how to get up and running with it you might be interested. The talk is taking place at the Marathon building downtown -- 539 S. Main St., Findlay, OH - Room 106M. More information is available at the
User Group site. Hope to see you there!
December 17, 2008 by
ryan
Oxitis [oks - ahy - tis]
-Noun
Acute or chronic anxiety toward sharing code online; this anxiety is usually caused by fear of public ridicule or excessive criticism regarding imperfections in code.
Origin:
2008, Josh Schwartzberg (n.); Oxitephobia; avoidance of placing imperfect code online; initially referring to Microsoft Oxite
November 13, 2008 by
ryan
Based on a great suggestion from Ben Scheirman and Simone Chiaretta I have converted the Gravatar URL helper class into a HtmlHelper extension method. This was my first stab at making a HtmlHelper extension but it seems to be working nicely and helps me keep my code a lot cleaner. Instead saving the URL (which I would highly advise against) or doing some weird method calling acrobatics in the Controller, I can simply say <%= Html.Gravatar("email@email.com") %> inside the view.
I've added a couple different method definitions for various parameters. You can pass in just an e-mail address, an e-mail and gravatar parameters (see here for more info on gravatar parameters) or an e-mail address, gravatar parameters and html attributes. A quick usage summary is listed below (I'm using my brother Joel's gravatar in the examples)
|
<%= Html.Gravatar("email@email.com") %>
Base Gravatar Helper
|
 |
|
<%= Html.Gravatar("email@email.com", new { s = "128", r = "pg" })%>
Gravatar helper with optional Gravatar Parameters
|
 |
|
<%= Html.Gravatar("email@email.com", null, new { style = "border:5px solid" })%>
Helper with HTML attributes. Please note, this is still expecting the Gravatar parameters -- you can pass in null if you want to just grab the default image with no additional properties.
|
 |
|
<%= Html.Gravatar("email@email.com", new { s = "128", r = "pg" }, new { style="border:5px solid;"})%>
Helper with both Gravatar parameters and HTML attributes
|
 |
Anyways, I've posted the class file below. Hopefully you find it useful -- I would love to hear what your thoughts are or of any changes you would like to see.
GravatarHelper.cs (2.72 kb)
November 9, 2008 by
ryan
UPDATE: See here
In the near future, I have a web project coming out that I've been working on for the past month or so. I'm not going to give too much detail on that just yet, however, in working on this project, I had to come up with a way for users to have profile images. I would rather not host these images on my server, I decided to leverage Gravatar (Globally Recognized Avatars).
There are a couple pre-existing options for dealing with gravatar in the .NET framework, however, I'm using the MVC framework -- standard ASP.NET controls are out of the question. After a brief look on the Gravatar site (specifically the page dealing with how the URL is constructed), it seemed like this would be a pretty easy task to write a class that I could use to get gravatar image paths. Below is the main part of the class I created to retrieve gravatar information based on an e-mail address:
public static string GetGravatarURL(string email, string size)
{
return (string.Format("http://www.gravatar.com/avatar/{0}?s={1}&r=PG",
EncryptMD5(email), size));
}
public static string GetGravatarURL(string email, string size, string defaultImagePath)
{
return GetGravatarURL(email, size) + string.Format("&default={0}", defaultImagePath);
}
private static string EncryptMD5(string Value)
{
System.Security.Cryptography.MD5CryptoServiceProvider md5 = new MD5CryptoServiceProvider();
byte[] valueArray = System.Text.Encoding.ASCII.GetBytes(Value);
valueArray = md5.ComputeHash(valueArray);
string encrypted = "";
for (int i = 0; i < valueArray.Length; i++)
encrypted += valueArray[i].ToString("x2").ToLower();
return encrypted;
}
All we're really doing is creating a URL based on the Gravatar path, an MD5 encrypted version of an e-mail address and some user specified parameters. For the methods, Size is how many pixels the image should be (up to 500) and defaultImagePath is the url to use as an alternate image if the user does not have a Gravatar image. There is a rating parameter also but for my site, I'm setting it to PG always.
This is not all that difficult but hopefully useful. I plan to continue writing examples as I make progress on the web application I mentioned.
September 21, 2008 by
ryan
Justin Etheredge recently posted a question for the community on his site. I think this is a good thing to think about because my definition of a good developer is one who continually tries to be better at their craft. My suggestions may be very similar to others but I would love to hear feedback.
Read : the first suggestion I have is a bit obvious. I like to read books and blogs on programming -- especially methodologies and architecture. Its hard to find good books becuase there seems to be an over saturation, many of which are not good. That being said, there are quite a few that I would still recommend : Head First Design Patterns, Don't Make Me Think (not really a programming book but important for anyone that writes applications with end-users) and Code Complete. Additionally I'm really looking foward to Beginning ASP.NET MVC by Simone and Keyvan. As for blogs, there are tons I subscribe to but a few I'll mention are Justin's, Jurgen Appelo's and Dustin Campbell's.
Share : I first started my site to help myself and hopefully others with programming topics. As I chose a subject to write about, I realized I did a lot more research than I would if it was just something I wanted to learn. Additionally, there was a lot of experience that I gained from the comments on the articles. Sharing information with a high level of transparency helps you become a better developer because you will get feedback on your work.
Set Goals : Set goals to learn new languages / techniques. I start off by reading blogs/books/articles then think of achievable pet project to use these new techniques on. The progress on the project can be used as the baseline for determining your progress. This is not saying you would be an expert in the new area but, in my opinion, is one of the best ways to learn.
There are tons of additional ways to become a better developer and I would love to hear your suggestions!
August 19, 2008 by
ryan
Tonight I have the privilege to be giving a talk on the ASP.NET MVC Framework at the
Northwest Ohio .NET User Group!
(6PM, at the HCR Manor Care building downtown)! If you interested in
learning about some of the reasons for using the MVC framework along
with creating a basic MVC application you might want to check it out :)