如何集成测试 Azure Web 作业?

How to integration test Azure Web Jobs?

我有一个 ASP.NET Web API 应用程序支持 Azure Web Job,其功能由 API 的控制器添加到存储队列的消息触发。使用 OWIN 测试 Web API 非常简单,但我该如何测试 Web 作业?

我 运行 测试时内存中的控制台应用程序 运行ner 吗?直接执行函数(虽然这不是一个合适的集成测试)?这是一项持续的工作,因此应用程序不会退出。更糟糕的是,Azure Web 作业函数无效,因此没有要断言的输出。

不需要运行内存中的控制台应用程序。你可以运行JobHost在你集成测试的内存中。

var host = new JobHost();

您可以使用 host.Call() 或 host.RunAndBlock()。您需要指向 Azure 存储帐户,因为本地主机不支持 Web 作业。 这取决于您的功能在做什么,但您可以手动将消息添加到队列、添加 blob 或其他任何内容。您可以通过查询您的 webjob 执行结果的存储等来断言

虽然@boris-lipschitz 是正确的,但如果您的工作是连续的(如 op 所说),您在调用 host.RunAndBlock() 后将无能为力。

但是,如果您 运行 主机在一个单独的线程中,您可以根据需要继续测试。虽然,您必须在测试结束时进行某种轮询才能知道作业何时有 运行.

例子
要测试的函数(从一个 blob 到另一个的简单复制,由创建的 blob 触发):

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

测试函数:

[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;
    }
}

我已经能够通过简单地执行以下操作非常轻松地模拟这个,它似乎对我来说工作得很好:

private JobHost _webJob;

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

WebJob 代码的样子:

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

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