Sunday, April 25, 2010

Coding Dojo XP Part 1: TDD & BDD with Nunit, WatiN, SpecFlow, and MVC 2.0


0

Saturday, I experienced my first coding dojo. I didn’t know what to expect, if I should prepare, what I should bring, etc. Well, I thought I’d let you know.

My experience was a good one. There were only 5 developers there, so it was easy to converse and ask questions. We talked about primarily TDD with nunit, moq, and WatiN. We also briefly talked about BDD with SpecFlow. It seems like you can’t really be prepared for a coding dojo. Just come with what you know and hopefully you’ll learn something new.

I brought my laptop this time, but ended up not pulling it out. Our dojo wasn’t like a typical coding dojo like the one talked about in the “How do you put on a coding dojo event?” video on YouTube. To learn more about coding dojos, check out codingdojo.org.

Now, for what I learned! I’m going to do 3 posts showing what we went over at the dojo. Part 1, this post, will be only about SpecFlow and how to set it up for your projects. Basically our leader/sensei came in and said pretend you were just handed a user story that says “Visitors to our website will be able to sign a guestbook”. So, with that user story in mind, we setup our SpecFlow. Here’s how:

1. Download SpecFlow

2. Run the installer

3. Create a new project called Dojo.Features (Dojo in our case, you can obviously call it whatever you want)

4. Add new SpecFlowFeature item to the project. We called it SignGuestBook.feature

image

5. SpecFlow provides an example, but this is what our’s looked like (NOTE: I couldn’t remember exactly what our’s looked like, but this is very similar :)

Feature: Sign
In order to sign our guestbook
As a visitor
I want to be able to say that I was at the site

Scenario: Sign Guestbook
Given I have filled out all required information
When I press sign
Then I should be redirected to the full list of guestbook entries and see a success message

As you can see, this is very readable and useful for BDD. The language used for the features is Gherkin, which is also used by Cucumber.

6. At this point, you can run your tests on the project. If you have Resharper, you can right-click the project name and click “Run Unit Tests”. If you have TestDriven.net, you can right-click and click “Run Test(s)”.

Obviously it will fail. Should look something like this:

image

7. Let’s make it pass. First we’ll copy the code it provides to us, which is this:

    [Binding]
public class StepDefinitions
{
[Given(@"I have filled out all required information")]
public void GivenIHaveFilledOutAllRequiredInformation()
{
ScenarioContext.Current.Pending();
}
}

8. Create a new SpecFlowStepDefinition item called SignGuestBookDefinitions. It will give you more samples, but we’re going to delete all of them. You could also just create an empty class and paste exactly what’s above in it, but I wanted to show you both ways.

So our final SignGuestBookDefinitions class should look like this:

using TechTalk.SpecFlow;

namespace Dojo.Features
{
[
Binding]
public class SignGuestBookDefinitions
{
[
Given(@"I have filled out all required information")]
public void GivenIHaveFilledOutAllRequiredInformation()
{
ScenarioContext.Current.Pending();
}
}
}

9. Run the tests again. It should fail again at the next step. Should look like this:

image

Notice the second line says –> pending: …

Then it goes on to the next step definition and fails because we haven’t set it up. Let’s do that now, here it is:

using TechTalk.SpecFlow;

namespace Dojo.Features
{
[
Binding]
public class SignGuestBookDefinitions
{
[
Given(@"I have filled out all required information")]
public void GivenIHaveFilledOutAllRequiredInformation()
{
ScenarioContext.Current.Pending();
}

[
When(@"I press sign")]
public void WhenIPressSign()
{
ScenarioContext.Current.Pending();
}

[
Then(@"I should be redirected to the full list of guestbook entries and see a success message")]
public void ThenIShouldBeRedirectedToTheFullListOfGuestbookEntriesAndSeeASuccessMessage()
{
ScenarioContext.Current.Pending();
}
}
}

If you reword your feature, you will need to change the matching attribute. There has to be a better way to set this up, but this was my first experience with SpecFlow and I’m basically recreating what we did on Saturday. So if you know another way or have blogged another way, please feel free to comment and your link!

10. Run the tests again and guess what, we fail again because everything is pending. It’s important to note that the given, when, then cascade, so you won’t always have an assert in each area.

11. Create your first implementation, which is our Given(). We used WatiN to do our testing for this part of the project, so you’ll need to download WatiN and reference it in the features project. Here’s what the first implementation looks like:

        [Given(@"I have filled out all required information")]
public void GivenIHaveFilledOutAllRequiredInformation()
{
var browser = new IE();
browser.GoTo(
"http://localhost:2345/guestbook/sign");
Assert.That(browser.Title, Is.EqualTo("Sign Guestbook"));
}

WatiN is a really cool UI testing tool. The two browsers that you can create an instance of are IE & Firefox. Generally speaking if it works in IE, it’s going to work in Firefox. So the next line is a goto, which tells WatiN to browse to that URL. Finally we do our nunit assert that the browser title matches “Sign Guestbook”.

12. Run your tests again and if you used IE instead of Firefox, you’ll most likely get this error:

“System.Threading.ThreadStateException: The CurrentThread needs to have it's ApartmentState set to ApartmentState.STA to be able to automate Internet Explorer. at WatiN.Core.IE.CheckThreadApartmentStateIsSTA()”

It’s REALLY annoying, but easily fixed. Just add an app.config file to your project and put this in it:

<?xml version="1.0" encoding="utf-8"?>
<
configuration>
<
configSections>
<
sectionGroup name="NUnit">
<
section name="TestRunner" type="System.Configuration.NameValueSectionHandler"/>
</
sectionGroup>
</
configSections>
<
NUnit>
<
TestRunner>
<!--
Valid values are STA,MTA. Others ignored. -->
<
add key="ApartmentState" value="STA" />
</
TestRunner>
</
NUnit>
</
configuration>

I also seem to remember our lead putting this “[assembly: NUnit.Framework.RequiresThread(System.Threading.ApartmentState.STA)]” at the end of the assemblyinfo.cs, but I didn’t find it necessary when re-creating the solution. I could’ve also just been imagining things…who knows.

13. Run your tests again and you should see IE launch and then your test fail because it doesn’t have anything at that URL yet. So you should get this error:

Expected string length 14 but was 44. Strings differ at index 0.

Expected: "Sign Guestbook"

But was:  "Internet Explorer cannot display the webpage"

14. Let’s make it pass.

  1. Add a new project to your solution, we used MVC 2.0, so that’s what I’m going to do now too. I’m going to call it Dojo.UI. Set the new project to be the startup project.
  2. Right-click the MVC project name and go to properties
  3. Click the Web tab, and click “Specific Port” and change the port to match the URL we are using above. In my case, 2345.
  4. Create a new Controller in the Controllers folder called “GuestbookController”
  5. Add a Sign method to the new controller that returns a ViewResult
  6. Create a new folder in the “Views” folder called “Guestbook
  7. Create a new View called Sign.aspx
  8. Change the title to be “Sign Guestbook”
  9. Hit F5 and add to the address bar guestbook/sign

Okay, now we’re all set up. Let’s run our tests again. Now our first step passes, but the others still fail. Well, I hate seeing red, but the other two are going to have to wait because we have to write a lot more unit tests and development to get those to pass. So what do we do? Well, I’m going to have to ignore them so our bar stays yellow and we know there are some more tests we have to touch. Let’s do that real quick.

In the app.config in the Dojo.Features project, make it look like this:

<?xml version="1.0" encoding="utf-8"?>
<
configuration>
<
configSections>
<
sectionGroup name="NUnit">
<
section name="TestRunner" type="System.Configuration.NameValueSectionHandler"/>
</
sectionGroup>
<
section name="specFlow" type="TechTalk.SpecFlow.Configuration.ConfigurationSectionHandler, TechTalk.SpecFlow"/>
</
configSections>
<
specFlow>
<
unitTestProvider name="NUnit" />
<
runtime missingOrPendingStepsOutcome="Ignore" />
</
specFlow>
<
NUnit>
<
TestRunner>
<!--
Valid values are STA,MTA. Others ignored. -->
<
add key="ApartmentState" value="STA" />
</
TestRunner>
</
NUnit>
</
configuration>

15. Let’s run our tests again. You should see this:

image

Okay, that was part 1 of my coding dojo experience. SpecFlow & WatiN are really cool tools and obviously you’ll see more of them in later posts because we still have two definitions to implement.

What’s next:

Part 2: TDD with nunit & moq. We’ll also start building out the sign page in our MVC project. I also might try to throw in EmitMapper for our mapping to see the differences between it and AutoMapper.

Part 3: Repository implementation with Fluent NHibernate

Hopefully you enjoyed this post as much as I enjoyed learning about this stuff at the dojo. Thanks for reading!

Download the Part 1 Solution

Shout it

kick it on DotNetKicks.com

blog comments powered by Disqus
Related Posts Plugin for WordPress, Blogger...