Azure Functions and SpecFlow

Anyone who follows my blog will know I am a big fan of Specflow for testing components. We usually use SpecFlow to compliment normal unit testing with some automated integration tests which combine the idea of “Does the component behave like we expect it to” with the opportunity to have some tested documentation describing the component behaviour.

Ive used Specflow for years when testing Web API and WCF Services and I was keen to use Specflow when coding Azure Functions within Visual Studio.

The main thing that is different between the types of service I mentioned earlier and functions is that normally you would develop web services to be hosted in IIS which gives you a few different activation options but the hosting is fairly easy. With functions you have a number of different bindings and they can be ran inside the Function host which runs as the executable Func.exe. If you are not familiar with Functions, the easiest way to see this is by pressing F5 in Visual Studio for your function project and you will see that the function host opens up and shows your functions running. The picture below shows the functions running in the emulator.

The problem is when it comes to automated testing how do you manage the function runtime emulator so that you can test your functions executing within the functions environment.

What we want to do is start up the function emulator before we run the tests and load our functions into it so that we can see they are registered and running. We will then execute the test against the resource our function binding is running against and test that the function behaves as expected.

The simplest example of this is if your function is using the http binding. This is how it may work:

  1. The tests will start and load up the functions in Func.exe
  2. Func.exe is now exposing my functions with http endpoints
  3. My Specflow test will begin executing
  4. At somepoint the step will call my function over http
  5. My function will execute and return a response
  6. My test will test the response
  7. MY test will test some other thing that the function was supposed to do (eg insert into a database)

At this point I know my unit testing has tested the lower level code and my Specflow test has tested that my code works properly when its deployed as an Azure Function.

How do I do it?

Ok so hopefully at this stage you like this idea and want to use it. This is how you implement it

Step 1 – Function Host Manager

First off I added a class to encapsulate the management of the function host. In this class we will use the .net Process class to start the external process Func.exe.

There are a couple of challenges we need to take care of:

  • Func.exe is installed by the Functions Cli which you get installing the tools for functions and sometimes when you F5 it will let you update to a newer version.
  • Depending on the Configuration mode you run the tests in you will need to change the path which you point Func.exe to so that it points at the right code to test. This is the release/debug stuff

You can see this class encapsulates this in 1 place so its easy to change if your scenario is different or if you want to use a different version of Func.exe. Unfortunately I haven’t found a better way to identify the latest version of the emulator. Maybe we can code something to iterate the folders and find the most recent or something.

Using this class you will basically call the StartHost and StopHost methods. The below code shows this class.

using System;
using System.Diagnostics;
using System.IO;
using System.Threading;

namespace Acme.AcceptanceTests.Shared
    public class FunctionHostManager
        private const string FunctionHostPath = @"%USERPROFILE%\AppData\Local\Azure.Functions.Cli\1.0.4\Func.exe";
        private static Process _functionHostProcess;

        public static string FunctionAppRootPath
                return @"..\..\..\Acme.FuncApp\bin\Debug\net461";
                return @"..\..\..\Acme.FuncApp\bin\Release\net461";
        public static void StartHost()
            var functionHostPath = Environment.ExpandEnvironmentVariables(FunctionHostPath);            
            var functionAppRootPath = Path.GetFullPath(FunctionAppRootPath);

            ProcessStartInfo startInfo = new ProcessStartInfo(functionHostPath);            
            startInfo.WorkingDirectory = functionAppRootPath;
            startInfo.Arguments = "host start";
            _functionHostProcess = Process.Start(startInfo);
            Thread.Sleep(new TimeSpan(0, 0, 10));
        public static void StopHost()


Step 2 – Specflow Test Operations

The next step is to plug this into the SpecFlow model. The easiest way to do this is a helper class which has the [Binding] attribute so SpecFlow picks it up. In this class you can use the [BeforeTestRun] and [AfterTestRun] attributes to make the methods run once at the very start before the first test and at the end after the last one. I considered options of starting before and after each scenario or feature but there is some spin up time for Func.exe so it makes more sense to start it all before executing any tests and keep it open until the end of the tests you wish to run.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using TechTalk.SpecFlow;

namespace Acme.AcceptanceTests.Shared
    public class TestRun
        [BeforeTestRun(Order = 1)]
        public static void Before()

        public static void After()


Rest of Tests

From here the rest of your Specflow tests are completely as normal. You don’t need any special attributes or anything, you just need to start the emulator before the tests and then in the test execute with the endpoints your functions use (eg http).


Hopefully this shows that it is very easy to enhance your development of Azure Functions by using specflow to ensure your code works the way you would expect it to on Azure and also get all of the other good stuff that Specflow brings to the party.

You May Also Like

About the Author: michaelstephensonuk