到目前为止,我已经能够为 Azure Functions 设置单元测试,并且效果很好。然而,对于我当前的项目,我需要使用动态或命令式绑定。https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-csharp#imperative-bindings https://learn.microsoft.com/en-us/azure/azure-functions/functions-reference-csharp#imperative-bindings
这导致我的单元测试出现问题,我似乎无法解决。
我的函数如下所示:
using Microsoft.Azure.WebJobs;
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.ServiceBus.Messaging;
using Newtonsoft.Json;
using System;
using System.IO;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
namespace My.Functions
{
public static class MyFunc
{
[FunctionName("my-func")]
public static async Task<HttpResponseMessage> Run([HttpTrigger(AuthorizationLevel.Function, "post", Route = null)] HttpRequestMessage req,
Binder binder)
{
dynamic data = await req.Content.ReadAsAsync<object>();
byte[] bytes = Encoding.UTF8.GetBytes(JsonConvert.SerializeObject(data));
MemoryStream stream = new MemoryStream(bytes, writable: false);
var sbMsg = new BrokeredMessage(stream) { ContentType = "application/json" };
var attributes = new Attribute[]
{
new ServiceBusAccountAttribute("some-sb-account"),
new ServiceBusAttribute("some-queue-or-topic", AccessRights.Send)
};
var outputSbMessage = await binder.BindAsync<IAsyncCollector<BrokeredMessage>>(attributes);
await outputSbMessage.AddAsync(sbMsg);
return req.CreateResponse(HttpStatusCode.OK, "OK");
}
}
}
在函数代码的末尾附近,我配置此绑定器来保存 BrokeredMessages 列表。这是通过调用活页夹上的 BindAsync 来完成的。
这些属性是动态设置的,包含服务总线连接和主题名称。当部署到 Azure 时,这一切都非常有效,因此功能方面一切都很好。
到目前为止,一切都很好。
然而,我正在努力让我的测试运行。为了能够调用该函数,我需要提供参数。 HttpTrigger 这很常见,但对于 Binder 我不知道要提供什么。
为了进行测试,我使用这种方法:
[TestMethod]
public void SendHttpReq()
{
// Setup
var httpRequest = GetHttpRequestFromTestFile("HttpRequest");
var sbOutput = new CustomBinder();
// Act
var response = SendToServicebus.Run(httpRequest, sbOutput);
// Assert
Assert.AreEqual(sbOutput.Count(), 1);
// Clean up
}
我使用从 Binder 继承的 CustomBinder,因为只有 Binder 实例在“BindAsync”函数中失败,抛出“对象引用未设置到对象实例”。看来绑定器的构造函数实际上并不应该被调用。
在 CustomBinder 中,我重写 BindAsync 以返回 BrokeredMessages 的通用列表。
public class CustomBinder : Binder
{
public override async Task<TValue> BindAsync<TValue>(Attribute[] attributes, CancellationToken cancellationToken = new CancellationToken())
{
return (TValue)((object)(new List<BrokeredMessage>()));
}
}
投掷也失败并不完全令人惊讶:
InvalidCastException:无法将类型“System.Collections.Generic.List”1[Microsoft.ServiceBus.Messaging.BrokeredMessage]”的对象转换为类型“Microsoft.Azure.WebJobs.IAsyncCollector`1[Microsoft.ServiceBus.Messaging.BrokeredMessage]” 。
我找不到 IAsyncCollector 的实现,所以也许我需要以不同的方式处理这个问题?
我的实际目标是能够验证代理消息列表,因为该函数将输出到 Azure 服务总线。