Gabriel Smoljar
Gabriel Smoljar

Reputation: 1236

How to integration test Azure Web Jobs?

I have a ASP.NET Web API application with supporting Azure Web Job with functions that are triggered by messages added to a storage queue by the API's controllers. Testing the Web API is simple enough using OWIN but how do I test the web jobs?

Do I run a console app in memory in the test runner? Execute the function directly (that wouldn't be a proper integration test though)? It is a continious job so the app doesn't exit. To make matters worse Azure Web Job-functions are void so there's no output to assert.

Upvotes: 3

Views: 3534

Answers (3)

Nagoh
Nagoh

Reputation: 813

I've been able to simulate this really easily by simply doing the following, and it seems to work fine for me:

private JobHost _webJob;

[OneTimeSetUp]
public void StartupFixture()
{
     _webJob = Program.GetHost();
     _webJob.Start();
}
[OneTimeTearDown]
public void TearDownFixture()
{
    _webJob?.Stop();
}

Where the WebJob Code looks like:

public class Program
{
    public static void Main()
    {
        var host = GetHost();
        host.RunAndBlock();
    }

    public static JobHost GetHost() 
    {
        ...
    }
}

Upvotes: 0

Dennis Holmer
Dennis Holmer

Reputation: 134

While @boris-lipschitz is correct, when your job is continious (as op says it is), you can't do anything after calling host.RunAndBlock().

However, if you run the host in a separate thread, you can continue with the test as desired. Although, you have to do some kind of polling in the end of the test to know when the job has run.

Example
Function to be tested (A simple copy from one blob to another, triggered by created blob):

public void CopyBlob(
    [BlobTrigger("input/{name}")] TextReader input,
    [Blob("output/{name}")] out string output)
{
    output = input.ReadToEnd();
}

Test function:

[Test]
public void CopyBlobTest()
{
    var blobClient = GetBlobClient("UseDevelopmentStorage=true;");

    //Start host in separate thread
    var thread = new Thread(() =>
    {
        Thread.CurrentThread.IsBackground = true;
        var host = new JobHost();
        host.RunAndBlock();
    });

    thread.Start();

    //Trigger job by writing some content to a blob
    using (var stream = new MemoryStream())
    using (var stringWriter = new StreamWriter(stream))
    {
        stringWriter.Write("TestContent");
        stringWriter.Flush();

        stream.Seek(0, SeekOrigin.Begin);

        blobClient.UploadStream("input", "blobName", stream);
    }

    //Check every second for up to 20 seconds, to see if blob have been created in output and assert content if it has
    var maxTries = 20;
    while (maxTries-- > 0)
    {
        if (!blobClient.Exists("output", "blobName"))
        {
            Thread.Sleep(1000);
            continue;
        }

        using (var stream = blobClient.OpenRead("output", "blobName"))
        using (var streamReader = new StreamReader(stream))
        {
            Assert.AreEqual("TestContent", streamReader.ReadToEnd());
        }
        break;
    }
}

Upvotes: 2

Boris Lipschitz
Boris Lipschitz

Reputation: 9516

There is no need to run console app in memory. You can run JobHost in the memory of your integration test.

var host = new JobHost();

You could use host.Call() or host.RunAndBlock(). You would need to point to Azure storage account as webjobs are not supported in localhost. It depends on what your function is doing, but you could manually add a message to a queue, add a blob or whatever. You could assert by querying the storage where your webjob executed result, etc.

Upvotes: 3

Related Questions