Tuesday, December 20, 2011

Slides from ANUG talk on Nancy

I did a talk on Nancy a week ago in the Aarhus -NET User Group. And in my own humble and unbiased opinion it went quite well :-) So I thought I'd share the slides with you - although they probably only make semi-sense without the talk to go along. Anyway here they are; enjoy.


Monday, December 5, 2011

Announcing: XmlUnit.Xunit


I wanted to announce a small library I have on my GitHub: XmlUnit.Xunit, which a library for testing against XML. It's a port of XmlUnit over to use Xunit.NET assertions instead of NUnit assertions, plus an addition of a fluent assertion style. The following is the projects README, and gives you a feel for the purpose of the project. Enjoy.

Intro

XmlUnit.Xunit provides Xunit.NET based assertions tailored to testing XML. The project contains assertions for comparing XML, applying XPath and XSLT expression to XML under test. All assertions come in two flavors: A traditional set of static assertion methods, and a fluent "should" style assertions.


Usage
You grab the source from here, download a build from here or install the NuGet package.

Beware that both the binary in the download tab and the NuGet package may give you assembly conflicts on Xunit.NET. To get around that you need an assmebly rebind of Xunit.NET.

Traditional Assertions
The traditional assertions in XmlUnit.Xunit er all static methods on the class XmlAssertion, and are used like this:

  404 [Fact]
  405 public void AssertStringEqualAndIdenticalToSelf()
  406 {
  407     string control = "<assert>true</assert>";
  408     string test = "<assert>true</assert>";
  409     XmlAssertion.AssertXmlIdentical(control, test);
  410     XmlAssertion.AssertXmlEquals(control, test);
  411 }
  412 
  413 private static readonly string MY_SOLAR_SYSTEM =
  414     "<solar-system><planet name='Earth' position='3' supportsLife='yes'/><planet name='Venus' position='4'/></solar-system>";
  415 
  416 [Fact]
  417 public void AssertXPathExistsWorksForExistentXPath()
  418 {
  419     XmlAssertion.AssertXPathExists("//planet[@name='Earth']",
  420                                    MY_SOLAR_SYSTEM);
  421 }
  422 
  423 [Fact]
  424 public void AssertXPathEvaluatesToWorksForMatchingExpression()
  425 {
  426     XmlAssertion.AssertXPathEvaluatesTo("//planet[@position='3']/@supportsLife",
  427                                         MY_SOLAR_SYSTEM,
  428                                         "yes");
  429 }
  430 
  431 [Fact]
  432 public void AssertXslTransformResultsWorksWithStrings()
  433 {
  434     string xslt = XsltTests.IDENTITY_TRANSFORM;
  435     string someXml = "<a><b>c</b><b/></a>";
  436     XmlAssertion.AssertXslTransformResults(xslt, someXml, someXml);
  437 }
  438 


Fluent Assertions
The fluent assertions are all extension methods with names starting with Should, and are used like this:

  404 [Fact]
  405 public void AssertStringEqualAndIdenticalToSelf()
  406 {
  407     string control = "<assert>true</assert>";
  408     string test = "<assert>true</assert>";
  409     test.ShouldBeXmlIdenticalTo(control);
  410     test.ShouldBeXmlEqualTo(control);
  411 }
  412 
  413 private static readonly string MY_SOLAR_SYSTEM =
  414     "<solar-system><planet name='Earth' position='3' supportsLife='yes'/><planet name='Venus' position='4'/></solar-system>";
  415 
  416 [Fact]
  417 public void AssertXPathExestsWorksForXmlInput()
  418 {
  419     new XmlInput(MY_SOLAR_SYSTEM)
  420         .XPath("//planet[@name='Earth']")
  421         .ShouldExist();
  422 }
  423 
  424 [Fact]
  425 public void AssertXPathEvaluatesToWorksForMatchingExpression()
  426 {
  427     MY_SOLAR_SYSTEM
  428         .XPath("//planet[@position='3']/@supportsLife")
  429         .ShouldEvaluateTo("yes");
  430 }
  431 
  432 [Fact]
  433 public void AssertXPathExistsWorksWithXpathFirstWithXmlInput()
  434 {
  435     var sut = new XmlInput(MY_SOLAR_SYSTEM);
  436 
  437     "//planet[@name='Earth']".AppliedTo(sut).ShouldExist();
  438 }
  439 
  440 [Fact]
  441 public void AssertXPathEvaluatesToWorksWithXPathFirst()
  442 {
  443     "//planet[@position='3']/@supportsLife"
  444         .AppliedTo(MY_SOLAR_SYSTEM)
  445         .ShouldEvaluateTo("yes");
  446 }
  447 
  448 [Fact]
  449 public void AssertXslTransformResultsWorksWithStrings()
  450 {
  451     string xslt = XsltTests.IDENTITY_TRANSFORM;
  452     string someXml = "<a><b>c</b><b/></a>";
  453 
  454     someXml.XsltTransformation(xslt).ShouldResultIn(someXml);
  455 }

Further Information
Is probably best gleened off the tests in this project, especially the tests for XmlAssertions and the tests for Should assertions.

Contribute
Please do! Fork, code, send pull request. :-)

Tuesday, November 8, 2011

Frictionless .NET Web App Development with Nancy Part IV - Hosting

Continuing my URL shortener sample (part I, II, III), I'll talk about one the things Nancy does quite differently from your average web framework: Nancys concept of hosting. At this point you may be thinking serves or clouds or storage etc, but that's not exactly what Nancy hosting is about.

Nancy Hosting
Nancy hosting is about which stack Nancy runs on top of. Such stacks include ASP.NET, WCF, OWIN, and self hosting. That means that a Nancy app can be run on top of any of those four hosts. You decide. So if you have an existing ASP.NET/IIS setup you can use it to run Nancy, if you have a WCF setup already you can use that.

The two last hosts may need a bit of introduction:

OWIN is Open Web Interface for .NET, which is an attempt to create a common interface between web frameworks and web servers. Currently it's not implemented by that many web servers, but could potentially allow web frameworks and the apps built on them to be move unchanged from one web server to another. One example of an OWIN compliant web server is Kayak, which can run on Mono. Combining these things means that our Nancy app can run on a stack of Nancy/Hosting.OWIN/Kayak/Mono/Linux. In other words a web app written in C# running on OSS all the way down. Who'd have thunk!

Self hosting is another interesting option: Self hosting means running a Nancy app in any .NET or Mono executable. This means that you can slap a web interface onto a desktop app or a windows service. Both of these possiblities are very interesting IMO.

Multiple Hosts - One Code Base
In the URL shortener sample I'd like to use the same application in two different settings: In a stand alone executable (just for kicks) and in ASP.NET stack. To do that I add two projects to my solution, one for each host:


First lets look at bit closer at the ASP.NET hosting project. I.e. the one called ShortUrlWebApp. It's simply an empty web project, as created by Visual Studio, with the Nancy.Hosting.Aspnet NuGet package and a project reference to ShortUrl added. Not one line of code wirtten. The project contains:


The Nancy.Hosting.Aspnet NuGet rewrites the web.config to make Nancy handle all incoming request. Nancy automatically picks up the Bootstrapper and Module in the ShortUrl assembly. That's all there is to running our url shortener on top of ASP.NET.

Second lets loot at the self hosting project. I.e. the one called ShortUrlDesktopApp. It's just a console application with a project reference to ShortUrl and the Nancy.Hosting.Self NuGet added:

In this case a little bit of work is needed in the program.cs - but not much, just instantiating and starting the NancyHost:

    1 namespace ShortUrlDesktopApp
    2 {
    3   using System;
    4   using Nancy.Hosting.Self;
    5   using ShortUrl;
    6 
    7   class Program
    8   {
    9     static void Main(string[] args)
   10     {
   11       ShortUrlModule artificiaReference;
   12       var nancyHost = new NancyHost(new Uri("http://localhost:8080/"));
   13       nancyHost.Start();
   14 
   15       Console.ReadKey();
   16 
   17       nancyHost.Stop();
   18     }
   19   }
   20 }

With this setup we can run the app on ASP.NET of from a console app. There is no difference in the browser and the application code is the same. This - IMO - is very cool indeed.

And the code is still on GitHub.