Site Meter
 
 

Monthly Archives: March 2010

Using HtmlUnit on .NET for Headless Browser Automation

If you subscribe to this blog, you may have noticed that I’ve been writing about test automation methods a lot lately. You could even think of it as a series covering different technical approaches:

The reason I keep writing about this is that I still think it’s very much an unsolved problem. We all want to deliver more reliable software, we want better ways to design functionality and verify implementation… but we don’t want to get so caught up in the beaurocracy of test suite maintenance that it consumes all our time and obliterates productivity.

Yet another approach

Rails developers (and to a lesser extent Java web developers) commonly use yet another test automation technique: hosting the app in a real web server, and accessing it through a fast, invisible, simulated web browser rather than a real browser. This is known as headless browser automation.

How is this beneficial?

  • It’s faster than driving a real browser. The simulated browser is just a native code library, so it’s very quick to launch and shut down, doesn’t require interprocess communication with your test suite, and doesn’t waste time physically drawing things on your screen, opening and closing pop-up windows, etc. Nonetheless, the simulated browser is full-featured: it exposes the usual HTML DOM API, runs JavaScript, evaluates CSS rules, and so on, so it’s still an effective way to specify rich client-side behaviours.
  • It’s more reliable than a real browser. Real browsers are complicated. For example, if you launch and shut down Firefox many times in rapid succession, occasionally it will fail to launch because a previous instance is still locking some file. Simulated browsers are totally independent, so don’t suffer these kinds of weirdness.
  • You can get more low-level control if you want it. For example, the simulated browser can easily offer an API to alter the HTTP headers it sends, or let you get or set the contents of its cache. A real browser wouldn’t usually make this easy.

And what drawbacks might you expect?

  • It can be harder to debug. Because you can’t physically see the browser on your desktop, it’s not as obvious what’s happening if a test fails (or passes) unexpectedly. Your debugger’s “immediate mode” will let you call the browser’s API to figure things out, but it can be a longer investigative process.
  • There’s no absolute guarantee that it faithfully replicates a real-world browser. For example, HtmlUnit can simulate multiple versions of Firefox, Internet Explorer, and Netscape, but it may not simulate every single quirk.

About HtmlUnit

HtmlUnit is a headless browser automation library for Java. It’s very well-developed and mature, as you can see from its extensive API. (Need to configure whether the user has JavaScript on or off? No problem.) It’s also the same technology that underlies Celerity, a Ruby library that exposes the Watir API but runs faster.

Unfortunately, in .NET world, we don’t have any good headless browser automation libraries like HtmlUnit that I know of. But don’t let that stop you! We do have IKVM – a near-magic way of running Java code on .NET (either by hosting a JVM on the CLR at runtime, or by a one-time conversion process that generates a native .NET assembly directly from the Java bytecode). So, why not use HtmlUnit itself?

Converting HtmlUnit to .NET

It’s surprisingly easy to get HtmlUnit, a Java library, converted into a native .NET assembly (no Java Virtual Machine needed!) using IKVM.

First, download HtmlUnit (as a compiled JAR file) from SourceForge (I’m using version 2.7), and extract all its files from the ZIP archive.

Second, download IKVM binaries from ikvm.net/SourceForge (I’m using version 0.42.0.3), and again extract all its files from the ZIP archive.

Open a command prompt, ensure you’ve added IKVM’s /bin folder to your PATH variable, change directory to HtmlUnit’s /lib folder, and then run ikvmc to convert the Java bytecode of all of the HtmlUnit JAR files into .NET bytecode. I ran this command:

ikvmc -out:htmlunit-2.7.dll *.jar

This produced a lot of warnings and a large (~10Mb) .NET assembly called htmlunit-2.7.dll. If you don’t want to bother with this process, you can download my sample project (linked below) which contains the .NET assembly I generated.

Using HtmlUnit from .NET

Once you’ve got htmlunit-2.7.dll as a .NET assembly, you can use it with any .NET unit testing library such as NUnit or XUnit. You will also need to reference a few of the IKVM runtime assemblies (I narrowed it down to six additional IKVM assemblies that appear to be needed – these are all included in IKVM’s /bin folder).

As a trivial example, here’s how you can use HtmlUnit with NUnit to load the Google homepage:

[TestFixture]
public class GoogleTests
{
    private WebClient webClient;
    [SetUp] public void Setup() { webClient = new WebClient(); }
 
    [Test]
    public void Can_Load_Google_Homepage()
    {
        var page = (HtmlPage)webClient.getPage("http://www.google.com");
        Assert.AreEqual("Google", page.getTitleText());
    }
}

Slightly more interesting, here’s how you can fill out a form (again, Google Search), click a button, and inspect the results:

[Test]
public void Google_Search_For_AspNetMvc_Yields_Link_To_Codeplex()
{
    var searchPage = (HtmlPage)webClient.getPage("http://www.google.com");
    ((HtmlInput)searchPage.getElementByName("q")).setValueAttribute("asp.net mvc");
    var resultsPage = (HtmlPage)searchPage.getElementByName("btnG").click();
 
    var linksToCodeplex = from tag in resultsPage.getElementsByTagName("a").toArray().Cast<htmlAnchor>()
                          let href = tag.getHrefAttribute()
                          where href.StartsWith("http://")
                          let uri = new Uri(href)
                          where uri.Host.ToLower().EndsWith("codeplex.com")
                          select uri;
    CollectionAssert.IsNotEmpty(linksToCodeplex);
}

As you can see, the API is full of Java idioms and feels a bit odd to a .NET developer. It would be great if someone decided to create a .NET wrapper library to expose a nicer API, .NET-style PascalCase, better use of IEnumerable and generics so LINQ queries were simpler, etc.

The other side of it is that HtmlUnit is very powerful. You can trivially scan the DOM with XPath, search for child elements, invoke events, much more easily than with WatiN.

To show that HtmlUnit has great JavaScript and Ajax support, here’s an example of automating a jQuery AutoComplete plugin to check its suggestions:

[Test]
public void jQuery_Autocomplete_Lon_Suggests_London()
{
    // Arrange: Load the demo page
    var autocompleteDemoPage = (HtmlPage)webClient.getPage("http://jquery.bassistance.de/autocomplete/demo/");
 
    // Act: Type "lon" into the input box
    autocompleteDemoPage.getElementById("suggest1").type("lon");
    webClient.waitForBackgroundJavaScript(1000);
 
    // Assert: Suggestions should include "London"
    var suggestions = autocompleteDemoPage.getByXPath("//div[@class='ac_results']/ul/li").toArray().Cast<htmlElement>().Select(x => x.asText());
    CollectionAssert.Contains(suggestions, "London");
}

In case you want to download all this code as a demo project you can run without needing IKVM or Java or anything weird, I’ve put it on GitHub.

Summary

This is experimental! I haven’t used this on any real project, though it was pretty effortless so far, so I’d definitely consider it. I don’t know how much faster HtmlUnit would be than a real browser, but it does bypass the trickiness of real browsers, which may be worth it alone. If I was going to use it seriously, I’d definitely make some .NET wrapper classes to hide the Java naming and idioms. HtmlUnit on .NET feels robust, but I haven’t pushed it hard.

kick it on DotNetKicks.com

Deleporter: Cross-Process Code Injection for ASP.NET

Deleporter is a little .NET library that teleports arbitrary delegates into an ASP.NET application in some other process (e.g., hosted in IIS) and runs them there. At the moment, it’s still pretty experimental, but I’ve found it useful so far.

Why would you want this? It’s mainly useful when you’re integration testing. Normally, integration tests can’t directly interact with your application’s code because it’s in a separate process (and possibly running on another machine). So, unlike unit tests, integration tests often struggle to test different configurations and have no option to use mocks.

Deleporter gets around that limitation. It lets you delve into a remote ASP.NET application’s internals without any special cooperation from the remote app (it just needs to include an extra IHttpModule in its config), and then you can do any of the following:

  • Cross-process mocking, by combining it with any mocking tool. For example, you could inject a temporary mock database or simulate the passing of time (e.g., if your integration tests want to specify what happens after 30 days or whatever)
  • Test different configurations, by writing to static properties in the remote ASP.NET appdomain or using the ConfigurationManager API to edit its <appSettings> entries.
  • Run teardown or cleanup logic such as flushing caches. For example,  recently I needed to restore a SQL database to a known state after each test in the suite. The trouble was that ASP.NET connection pool was still holding open connections on the old database, causing connection errors. I resolved this easily by using Deleporter to issue a SqlConnection.ClearAllPools() command in the remote appdomain – the ASP.NET app under test didn’t need to know anything about it.

Rails developers can already do this either by hosting their app in-process (e.g., with WebRat) or using a cross-process mocking tool. I’ve already talked about hosting ASP.NET (MVC) apps in-process with integration tests (the starting point for this code); now I wanted to get the same benefits while hosting my app on a real web server.

This library is built on regular .NET remoting. But unlike regular remoting, it run arbitrary delegates, not just methods specifically exposed by the remoting service. If the code for your delegate isn’t already loaded into the ASP.NET appdomain, Deleporter will serialize the code and send it across. This is really essential for being useful from an integration test suite, because the test code wouldn’t normally be in the real app.

Enough talk! Code now.

To use it, first download the binary or compile the source to get Deleporter.dll. Reference it from both your integration test project and the ASP.NET MVC/WebForms app you’re testing.

Next, to get your ASP.NET app to listen for commands, edit its Web.config file to reference this extra HTTP module:

<configuration>
  <system.web>
    <httpModules>
      <!-- If you're using Visual Studio's built-in web server, or IIS 5 or 6, add this: -->
      <add name="DeleporterServerModule" type="DeleporterCore.Server.DeleporterServerModule, Deleporter" />
    </httpModules>
  </system.web>
  <system.webServer>
    <modules>
      <!-- If you're using IIS 7+, add this: -->
      <add name="DeleporterServerModule" type="DeleporterCore.Server.DeleporterServerModule, Deleporter" />
    </modules>
  </system.webServer>
</configuration>

Now, when you next start up your ASP.NET app, it will listen on TCP port 38473 – a randomly-chosen default – for commands from your integration test suite.

In your integration test code, you can now run arbitrary delegates in the remote ASP.NET app, sending both data and code into it, and optionally pulling data back. As a trivial example, you can pull back the server’s time local time:

[Test]
public void ServerClockHasCorrectYear()
{
    DateTime serverTime = Deleporter.Run(() => DateTime.Now);
    Assert.AreEqual(DateTime.Now.Year, serverTime.Year, "The server's clock is way off");
}

You can use multi-statement lambdas, too, even if they capture locals from the containing method. Deleporter will send the captured locals into the remote app (as long as they’re serializable), and if the remote app edits them, it will pull back the new values and update your locals. In other words, anonymous methods and multi-statement lambdas work with captured local variables just as if all the code was running locally. Example:

[Test]
public void SendingAndUpdatingCapturedLocals()
{
    DateTime serverTime = default(DateTime);
    string fileToLocate = "~/web.config";
    string mappedPhysicalPath = null;
 
    Deleporter.Run(() => {
        // This code, which both reads and writes locals from the outer scope,
        // runs in the remote ASP.NET application
        serverTime = DateTime.Now;
        mappedPhysicalPath = HostingEnvironment.MapPath(fileToLocate);
    });
 
    Assert.AreEqual(DateTime.Now.Year, serverTime.Year);
    Assert.IsTrue(File.Exists(mappedPhysicalPath)); // Of course, this will only be true if the ASP.NET app runs on the same machine as the integration test code
}

More realistic applications

So far I’ve only shown very artificial examples designed to illustrate the syntax. To give you a more realistic idea of how you could apply it, I can offer two sample applications.

  • A very simple ASP.NET MVC app called WhatTimeIsIt whose sole behaviour varies according to the date. Like all good ASP.NET MVC applications, it uses the Dependency Injection pattern (in this example, with Ninject) to get the current date & time from an IDateProvider – the default implementation of which just returns DateTime.Now.
    It has simple integration tests that use Deleporter and Moq to inject a mock IDateProvider across the process boundary while the app is running, and then verifies some behaviour that only happens during specific dates. It also demonstrates an easy way of tidying up after the tests run (restoring the original IDateProvider) automatically without cluttering the test code with teardown logic.
    Here’s how the cross-process mocking works:
    // Inject a mock IDateProvider, setting the clock back to 1975
    var dateToSimulate = new DateTime(1975, 1, 1);
    Deleporter.Run(() => {
        var mockDateProvider = new Mock<idateProvider>();
        mockDateProvider.Setup(x => x.CurrentDate).Returns(dateToSimulate);
        NinjectControllerFactoryUtils.TemporarilyReplaceBinding(mockDateProvider.Object);
    });
  • An enhanced version of the SpecFlow BDD-style integration test suite from my previous blog post. It now uses Deleporter to apply a mock repository to verify certain specifications.
    For example, one of the Gherkin files now specifies this scenario:
    Scenario: Most recent entries are displayed first
    	Given we have the following existing entries
    		| Name      | Comment      | Posted date       |
    		| Mr. A     | I like A     | 2008-10-01 09:20  |
    		| Mrs. B    | I like B     | 2010-03-05 02:15  |
    		| Dr. C     | I like C     | 2010-02-20 12:21  |
          And I am on the guestbook page
        Then the guestbook entries includes the following, in this order
    		| Name      | Comment      | Posted date       |
    		| Mrs. B    | I like B     | 2010-03-05 02:15  |
    		| Dr. C     | I like C     | 2010-02-20 12:21  |
    		| Mr. A     | I like A     | 2008-10-01 09:20  |

Gotcha: What you must remember to avoid confusing problems

One behaviour might surprise you at first. It’s certainly caught me out plenty of times already. Each time you edit and recompile your integration test code, you must also recycle your ASP.NET appdomain (e.g., by resaving its Web.config file, or the nuclear option – running iisreset) otherwise the old code will still be loaded into it. That’s because, as far as I’m aware, there’s no way to unload an assembly from a .NET appdomain. Once your delegates have been transferred over, they’re staying there and can’t automatically be replaced by newer versions.

This isn’t a problem if you’re running an integration suite through your continuous integration (CI) system – the app code would be recompiled and hence reset between test suite runs. It’s only something to watch out for during local development. In the Deleporter.Test.Client project I’ve shown a crude but working way of automatically recycling the ASP.NET appdomain when the test suite starts running; you may be able to work out a better way of automating this if you need one.

Important security note

You should not enable DeleporterServerModule on a production web site. It’s only supposed to be used in dev and QA environments, because it’s literally an invitation to upload and execute arbitrary code.

To reduce the chance of a mistake, DeleporterServerModule will refuse to run if your web site was compiled in release mode – it will demand that you remove the IHttpModule from your Web.config file. Technically you should be OK if your firewall doesn’t accept inbound connections on port 38473 (or whatever port you configure it to listen on) anyway. Obviously, no warranties, you use it at your own risk, etc.

License: Ms-Pl

kick it on DotNetKicks.com

Behavior Driven Development (BDD) with SpecFlow and ASP.NET MVC

Test Driven Development (TDD) has been around for about a decade, and has been mainstream for at least five years now. During this time, TDD practitioners have been gradually changing and refining the methodology, the mindset, and the terminology in an effort to increase its usefulness and avoid some of the problems that newcomers often experience.

The mindset and terminology has shifted so much that some folks have started using a new name for the updated methodology: BDD. Here’s a brief overview*:

  • Test Driven Development seeks to improve software quality by getting you to follow an iterative workflow often called red-green-refactor. In theory, it keeps quality high because if any change breaks earlier functionality, you should be notified by way of a failing test. Also, it should help you to make more pragmatic decisions about what code to write, because you only write the simplest code needed to make all your tests pass.
    Despite its unfortunate name, it became clear over time that TDD’s greatest potential benefit is not as a technique for testing code or detecting bugs, but in fact as a code design aid, because it provides a precise mechanism for specifying how your code should behave before you get mentally caught up in the actual implementation. However, in reality, I’ve seen many developers still struggle to break free from a test-oriented mindset and continue to amass reams of unit tests that simply exercise every possible code path without usefully describing what this proves or why it represents correct behaviour. This doesn’t aid design, very rarely detects bugs, and yet consumes a huge amount of maintenance time.
  • Behaviour Driven Development retains the basic red-green workflow, but dramatically puts the emphasis on specifying behaviours that are understandable to people (often, business domain experts). It addresses questions such as “How much should I specify?” and “How should I organise and name my specifications so they are most useful?”
    To do this, BDD says you should elevate your mind to a level of behavioural abstraction above the code implementation. So don’t say “Constructor_Test” or even  “Constructor_NullParam _ThrowsArgumentNullException” but instead say “A shipment cannot be created without a recipient address”. The change of emphasis and terminology leads people to write more useful specifications.
    I won’t focus on the term BDD itself, because the term is not hugely useful: nobody has ever given it a precise definition as far as I’m aware, and there isn’t a lot of consensus about what it should mean (some say it should only be about the UI; others say not). Instead, in this blog post, I’m going to focus on the major tools that have come out of the BDD stable and the advantages they can give you.
Unit level or UI level?

You can write BDD-style specifications about individual code units, in which case you’ll  probably use a context/specification style framework like RSpec (for Ruby) or in .NET something like MSpec or SpecUnit (personally, I don’t like either). Unit-level specifications work brilliantly for most code that ultimately exposes an API for other code. But personally, I spend most of my time writing UI code, usually with ASP.NET MVC, and UI code is fundamentally different. It isn’t about producing an API – it’s about producing user experience (UX) behaviours. These behaviours typically aren’t atomic (contained within a single click or HTTP request); their essence exists only across a sequence of interactions. As such, unit-level specifications can fall short and fail to capture the UI behaviours you have in mind. I wrote before about why, in real projects, I’ve found unit tests to be of limited value for ASP.NET MVC controllers.

Alternatively, you can write BDD-style specifications about UI interactions. Assuming you’re building a web application, you’ll probably use a browser automation library like WatiR/WatiN or Selenium, and script it either using one of the frameworks I just mentioned, or a given/when/then tool such as Cucumber (for Ruby) or SpecFlow (for .NET). In this blog post, I’ll describe these tools and provide an example based on ASP.NET MVC.

* I don’t claim to be an authority on BDD, so if you think I’ve got this all wrong, I invite you to come along and tell me what I’ve misunderstood. Try to be specific, please. My existing understanding is based on having done a lot of TDD, seeing its limitations especially in large teams, and recognising that some of these BDD ideas look like they could help with that.

So, what’s Cucumber?

image Cucumber is a Ruby tool that offers a natural-language way to specify behaviours in terms of “Given, When, Then” (GWT) sentence fragments. This language is called Gherkin. You create a plain-text file (called a “.feature” file) containing a set of scenario definitions written in Gherkin, for example

Scenario: Show logged in user name
  Given I am logged in as a user called "Steve"
   When I visit the homepage
   Then the page header displays the caption "Hello, Steve!"

… and also provide Ruby scripts that define what the runner should do when it hits matching steps, for example

Given /I am logged in as a user called "(.*)"/ do |name|
    create_user(name)
    sign_in_as(name)
end
 
...
 
Then /the page header displays the caption "(.*)"/ do |caption|
    page_header.should_contain(caption)
end

The syntax is extremely flexible: Cucumber only cares about the Gherkin keywords “Given”, “When”, “Then”, “And” (plus a few others); everything else is simply matched against your regular expressions. Any tokens captured by capture groups in your regexes are passed to your step definition blocks as parameters. For web applications, it’s normal for your step definitions to work by using a browser automation library such as WatiN/WatiR or Selenium.

When you invoke Cucumber, it finds, parses and runs your .feature files, reporting the results (success in green, pending in yellow, failure in red):

image

Because the GWT model inherently describes sequences of interactions, and because natural-language .feature files are inherently decoupled from the implementation code (they don’t mention the name of any classes or methods), this whole approach is a perfect fit for UI automation rather than unit-level testing. 

Because you can describe scenarios in the language of your domain and user interface, your resulting feature files should make perfect sense to business experts. So, unlike traditional unit test driven development, this methodology can finally deliver on the promise of executable specifications that are actually useful as documentation.

Doing it in .NET with SpecFlow

image

As I mentioned, Cucumber itself is a Ruby tool. At the end of this blog post I’ll discuss some options for running the original Cucumber tool in a .NET environment, but for now let’s forget about that – you can sidestep all that complexity with SpecFlow.

SpecFlow is an open-source .NET tool that lets you write specifications using 100%-Cucumber-compatible Gherkin syntax, and has a number of advantages over Cucumber itself:

  • It integrates with Visual Studio, which means you get File->New templates for creating new feature files
  • More crucially, it gives complete VS debugger support, so you can set breakpoints on Given/When/Then lines in your .feature files and step through their execution
  • You can implement your step definitions in any .NET language
  • When you compile a project containing SpecFlow feature files, the output is an NUnit test assembly, so you can use your favourite NUnit-compatible test runner or existing CI infrastructure to run the specifications with no additional configuration.
  • It doesn’t have such a ridiculous name :) It’s sad, but at one of my recent clients, several managers refused to take Cucumber seriously and wouldn’t pay attention to Cucumber specifications purely because of the name. That’s the real world for you!

Example: Combining ASP.NET MVC, SpecFlow, and WatiN

To give you something concrete to get started with, I’ve made a very simple ASP.NET MVC 2 example application, built following the BDD workflow and with a full set of specs. To try it out,

You should easily be able to understand in high-level terms what the application does by reading the Gherkin specifications. Just imagine these specifications are the written result of a design meeting where you’ve got your client or boss to tell you how the user interactions should work.

Feature: Browsing
   In order to see who's been on the site
   As a user
   I want to be able to view the list of posts

Scenario: Navigation to homepage
   When I navigate to /Guestbook
   Then I should be on the guestbook page

Scenario: Viewing existing entries
   Given I am on the guestbook page
   Then I should see a list of guestbook entries
    And guestbook entries have an author
    And guestbook entries have a posted date
    And guestbook entries have a comment
Feature: Posting
   In order to express my views
   As a user
   I want to be able to post entries into the guestbook

Scenario: Navigation to posting page
   Given I am on the guestbook page
   Then I should see a button labelled "Post a New Entry"
   When I click the button labelled "Post a New Entry"
   Then I am on the posting page

Scenario: Viewing the posting page
   Given I am on the posting page
   Then I should see a field labelled "Your name"
    And I should see a field labelled "Your comment"

Scenario: Posting a valid entry
   Given I am on the posting page
     And I have filled out the form as follows
       | Label          | Value             |
       | Your name      | Jakob             |
       | Your comment   | Das ist gut!      |
   When I click the button labelled "Post"
   Then I should be on the guestbook page
    And I see the flash message "Thanks for posting!"
    And the guestbook entries includes the following
       | Name      | Comment      | Posted date          |
       | Jakob     | Das ist gut! | (within last minute) |

Whenever you hit save while editing one of these files, SpecFlow generates a C# NUnit test fixture containing a [Test] method for each scenario. You don’t have to know or care about that, though. All you have to do is create step definitions in C# to match the lines in the Gherkin files.

At first, you won’t have any matching step definitions, so the NUnit test runner will show the tests as “inconclusive”:

image

Notice that in the “Text Output” tab it provides C# stub code to create a matching step definition. Here’s some examples of the finished step definitions, written using WatiN to automate a browser:

[When(@"I navigate to (.*)")]
public void WhenINavigateTo(string relativeUrl)
{
    var rootUrl = new Uri(ConfigurationManager.AppSettings["RootUrl"]);
    var absoluteUrl = new Uri(rootUrl, relativeUrl);
    WebBrowser.Current.GoTo(absoluteUrl);
}
 
[Then(@"I see the flash message ""(.*)""")]
public void ThenISeeTheFlashMessage(string message)
{
    var flashElement = WebBrowser.Current.Element("flashMessage");
    Assert.That(flashElement.Text, Is.EqualTo(message));
}
 
[Given(@"I have filled out the form as follows")]
public void GivenIHaveFilledOutTheFormAsFollows(TechTalk.SpecFlow.Table table)
{
    foreach (var row in table.Rows) {
        var labelText = row["Label"] + ":";
        var value = row["Value"];
        WebBrowser.Current.TextFields.First(Find.ByLabelText(labelText)).TypeText(value);
    }
}

There’s lots more I could say about WatiN syntax and Gherkin best practices, but this is a pretty long post already so I’ll leave that to others.

In case anyone’s wondering, I’m not trying to claim with this post that Cucumber-style UI automation tests are the one true way to do BDD, or that unit testing is dead. UI automation tends to be much more difficult to do than unit-level tests, because there are many more moving parts and you have to concern yourself with test data, setup and teardown, etc. Seriously, it is hard work, and requires a lot more persistence and dedication than mere unit testing, though it can also give many extra benefits especially with regard to detecting regressions.

What about Running Cucumber Itself on .NET?

If, for some reason, you don’t want to use SpecFlow and would rather run the original Ruby-based Cucumber tool, there are two main options for .NET programmers:

  • Use IronRuby. The current version of IronRuby is entirely capable of running Cucumber. It isn’t as easy to set up as SpecFlow, but only took me 30 minutes or so. The drawbacks are that (1) you have to write step definitions in Ruby, unless someone can come up with a clever way to call arbitrary .NET methods directly, (2) it runs Cucumber pretty slowly, at least in my testing, and (3) it doesn’t trivially integrate with existing CI infrastructure like an NUnit-based solution does.
  • Use Cuke4Nuke. This is an open-source project that aims to bridge the gap between the original Cucumber tool running on any Ruby interpreter (not necessarily IronRuby) and step definitions written in .NET. It works by hosting your .NET step definitions in a small .NET-based “server” application, which Cucumber communicates with over a TCP/IP connection. I must admit I had a bad experience trying to make this work – it took hours. The latest Ruby interpreter didn’t include all the necessary libraries for Cuke4Nuke, and then when I’d hacked all the dependencies together, it wasn’t clear to me where to put the magic “cucumber.wire” file or what parameters you can use with the .NET server app. And then it was also pretty slow compared to keeping everything in .NET with SpecFlow. And it had a very limited API for running setup/teardown code around scenarios.

If you want to write step definitions in a .NET language, I don’t know why you wouldn’t just use SpecFlow. Since it’s 100% Gherkin-compatible, your feature files could in future be moved to a different implementation if desired. If you’ve tried others, I’d be interested to hear about your experiences. And no, I haven’t tried Spectre yet.

Injecting Mocks into a Running ASP.NET Application

In the next post, I’ll show you one possible way to simplify or speed up UI-level specifications a little. It’s a cross-process code injection library that, among other things, you can use to inject a mock database into a running ASP.NET application without it knowing about it. Or, you can override configuration, or maybe simulate the passing of time.

Sometimes, it isn’t desirable to meddle with your app’s internals, but sometimes it is. Ruby coders can already do it using Webrat or cross-stub, and I’ve found reasons to want that power over .NET apps too.

kick it on DotNetKicks.com