NancyFx

Most complex software products are integrating with external applications.

There are many examples like aviation systems which are obtaining weather data from external providers, financial applications exchanging data with bank systems or monitoring systems fetching data from servers or applications.

There are many ways to implement such interoperability between systems and one of them with is very popular is REST API.

E2E tests with real external systems are always required to some extent but most cases could be automated and run regularly without external dependencies to simplify test environment and make tests faster and more reliable.

Here we should distinguish two ways of integration from our system/application point of view:

  • sending requests to external REST APIs and processing response
  • receiving requests from external REST APIs and sending proper response

In this post I would like to focus on the former so testing processing response from external service by our application under test. To achieve it, it's needed to replace external API by mock REST service which can receive our request and return back response which our application can further process.

Solution I've used in one of the projects I worked on was Nancy - lightweight web framework for .net.

Requirements I have:

  • My application under test is price monitoring application which help people to not miss promotions on web stores
  • User creates list of products to monitor with expected price which should trigger some actions (e.g. send notification)
  • Once the list is created, our application is sending REST request to external web stores to check current price -> because prices are changing all the time, it's hard to prepare test data which triggers always expected conditions - this is good place for mocking external service

Solution:

  • Create new .net core project and install Nancy package

    dotnet add package Nancy
  • Create some static data to be returned by API

    public class MusicStore
    {
    public MusicStore()
    {
        Guitars = new List<Guitar>
        {
            new Guitar { Id = 1, Type = "Classical", FretCount = 17, StringCount = 6, Price = 900.99 },
            new Guitar { Id = 2, Type = "Electric", FretCount = 22, StringCount = 6, Price = 2899.50 },
            new Guitar { Id = 3, Type = "Bass", FretCount = 22, StringCount = 5, Price = 1400.67 }
        };
    }
    public List<Guitar> Guitars { get; }
    }

    where Guitar is a model of item for monitoring

    public class Guitar
    {
    public int Id { get; set; }
    public string Type { get; set; }
    public int StringCount { get; set; }
    public int FretCount { get; set; }
    public double Price { get; set; }
    }
  • now it's time for main part - creating controller which has two REST API GET methods which will be called by our system under test

    • /guitars which should return all guitars as a JSON list
    • /guitars/{id} where {id} is integer values e.g. /guitars/1 which should return item with id as a JSON object

    Thanks to Nancy, code to achieve this is extremely easy and self-explaining

    public sealed class GuitarsController : NancyModule
    {
    private readonly MusicStore _musicStore = new MusicStore();
    
    public GuitarsController()
    {
        Get("guitars/", parameters =>
        {
            return Response.AsJson(_musicStore.Guitars);
        });
    
        Get("guitars/{id:int}", parameters =>
        {
            return Response.AsJson(_musicStore.Guitars.Where(g => g.Id == parameters.id));
        });
    }
    }

    Of course proper packages needs to be imported

    using Nancy;
    using System;
    using System.Linq;

    and our data store, in this case using qa_services.nancy_example.Data;

  • we have implemented controller but it's needed also to host service. I've chosen self hosting with Kestrel which requires adding only few lines of code in two files

    public class Startup
    {
    public void Configure(IApplicationBuilder app)
    {
        app.UseOwin(x => x.UseNancy());
    }
    }

    which requires following packages:

    using Microsoft.AspNetCore.Builder;
    using Nancy;
    using Nancy.Owin;

    and in Program.cs

    public static void Main(string[] args)
    {
    var host = new WebHostBuilder()
        .UseContentRoot(Directory.GetCurrentDirectory())
        .UseKestrel()
        .UseStartup<Startup>()
        .Build();
    
    host.Run();
    }

    with

    using Microsoft.AspNetCore.Hosting;
    using System.IO;
  • last thing is to build and run our new REST service and to configure our system under test to send request to Nancy service instead of to external application

Full project is available on github