In my previous posts, we had a look at testability for serverless applications. In this post, we’re going to apply a similar approach to Azure WebJobs.

The sample code used in this post can be found here.

For either scheduled WebJob instance or on-demand WebJob instance, it’s just a console application that we’re not dealing with. However, when we look at the continuous running WebJob instance, it will be a different story. Let’s have a look at the basic WebJob code.

This is the main WebJob host entry. Within the Main() method, it creates the JobHostConfiguration instance and JobHost instance for a WebJob application that is continuously running. This is the actual WebJob function.

As we can see, it has the static modifier, which make us hard to test. We can use the service locator pattern for this static method to cope with testability like Azure Function triggers. However, this should only apply when the service locator is the only option. Luckily, Azure WebJobs provides an interface called IJobActivator, which helps us easily integrate WebJob with an IoC container. WebJobActivator.Autofac is one of implementations of the IJobActivator with Autofac. Let’s have a look how the NuGet package has implemented the interface.

DISCLAIMER: I am the author of the NuGet package, WebJobActivator.Autofac.

Extending IJobActivator

When we decompile the IJobActivator interface, we see that it contains only one method CreateInstance(), which is insufficient for any IoC container library because we need to register dependencies beforehand. Therefore, we need to extend the interface, called IWebJobActivator. The new interface declares another method, RegisterDependencies(THandler handler = default(THandler)).

As the RegistrationHandler class is optional, so we can omit it for actual implementation. But the handler is rather useful for unit testing. We’ll touch this later in this post. Here’s the abstract class that implements IWebJobActivator:

As we can see, the implemented method barely does registration. We need an IoC container library here.

Integrating with Autofac

Now, let’s implement the extended interface with Autofac. Here’s the actual implementation:

With Autofac, the AutofacJobActivator does actual dependencies registration process. One of the most powerful features that Autofac offers is Module. We can register dependencies by grouping as a module. For our purpose, the RegistrationHandler can be a perfect place to implement this module. Here’s the handler implementations:

As we can see, AutofacRegistrationHandler implements a property of Action to register a module. Here’s the sample module:

We’re all set. Let’s change the Program.cs to apply IJobActivator.

Enabling IJobActivator

The Main() method can be modified like this:

Inside the method, we instantiate AutufacRegistrationHandler and register WebJobModule, instantiate AutofacJobActivator and register dependencies using the handler, and add the activator to JobHostConfiguration. Now, we can finally remove all the static modifier from the function class:

So far, we’ve extended IJobActivator to IWebJobActivator and implemented AutofacJobActivator to configure JobHost. However, I’m still not happy because there are two instances remain tightly coupled within the Main() method – JobHostConfiguration and JobHost. We also need to decouple those two instances.

Implementing JobHostConfigurationBuilder

JobHostConfigurationBuilder is basically a wrapper class of JobHostconfiguration, with a fluent method, AddConfiguration(Action). Let’s have a look.

This builder class gets the activator instance as a parameter and internally creates an instance of the JobHostConfiguration. Now, we’ve got JobHostConfiguration decoupled. Let’s move on.

Implementing JobHostBuilder

This is the last step. JobHostBuilder is another wrapper class of JobHost and here’s the implementation.

Nothing special. It gets the JobHostConfigurationBuilder, internally creates a JobHostConfiguration instance, create a JobHost instance, and run the host instance. This now needs to be integrated with Autofac like:

AutofacJobHostBuilder accepts Autofac’s module instance which help register dependencies. We’ve all set now. Let’s make another change on the Program.cs:

Putting Them Altogether

This is the final version of Program.cs with full testability.

As a static property, WebJobHost gets the AutofacJobHostBuilder class with dependencies and additional configurations. After that, within the Main() method, it builds JobHost and runs the instance. While performing unit tests, this Program.cs can be also testable by mocking and injecting a dependency of IJobHostBuilder like:

So far, we’ve walked through how an Azure WebJob application can be written by being decoupled and considering testability. With this approach, we don’t even need to run Storage Emulator in our local environment for testing. Happy coding!

Category:
Application Development and Integration
Tags:
, , ,