我无法在集成测试中以编程方式本地启动Azure功能。
我读到的第一篇文章是:
programmatically-starting-function-app-is-failing-without-descriptive-output
可是却根本帮不上忙。
这是我的职责:
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.Functions.Worker;
using AdmGroup.Omega.Framework.Net.Mail;
using Newtonsoft.Json;
namespace AdmGroup.Omega.Services.Infrastructure.EmailFunction.Functions;
public class EmailService
{
private readonly IMailMessageSender mailMessageSender;
public EmailService(IMailMessageSender mailMessageSender)
{
this.mailMessageSender = mailMessageSender;
}
[Function("EmailService")]
public async Task<IActionResult> Run
(
[RabbitMQTrigger(queueName: "EmailQueue", ConnectionStringSetting = "admgroup:omega:services:infraestructure:emailservice:rabbitmq")] MailMessage email)
{
var strEmail = JsonConvert.SerializeObject(email);
Console.WriteLine(strEmail);
await mailMessageSender.SendAsync(email);
return new OkResult();
}
}
这是Program.cs(我在其中配置依赖项注入):
using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.DependencyInjection;
using AdmGroup.Omega.Framework.EmailServicing.Services;
using AdmGroup.Omega.Framework.Net.Mail;
using AdmGroup.Omega.Framework.Security;
using Azure.Security.KeyVault.Secrets;
using Microsoft.Extensions.Configuration;
using Azure.Identity;
var config = InitConfiguration();
var clientId = config["AzureKeyVault:ClientId"];
var keyVaultUrl = config["AzureKeyVault:KeyVaultUrl"];
if (!string.IsNullOrEmpty(clientId) && !string.IsNullOrEmpty(keyVaultUrl))
{
var tokenCredential = new DefaultAzureCredential(new DefaultAzureCredentialOptions { ManagedIdentityClientId = clientId });
var host = new HostBuilder()
.ConfigureFunctionsWorkerDefaults()
.ConfigureServices(s => s.AddSingleton<SecretClient>(_ => new(new Uri(keyVaultUrl), tokenCredential)))
.ConfigureServices(s => s.AddSingleton<AzureKeyVaultSecretManager>())
.ConfigureServices(s => s.AddSingleton<IMailMessageSender, Office365GraphEmailService>())
.Build();
await host.RunAsync();
}
/// <summary>
/// Allow test project to use an appsettings.json file.
/// Read RabbitMQ host and queue name from test appsettings
/// </summary>
/// <returns>Configuration</returns>
static IConfiguration InitConfiguration()
{
return new ConfigurationBuilder()
.AddJsonFile("local.settings.json")
.AddEnvironmentVariables()
.Build();
}
public partial class Program { }
如果我逃跑
func host start --dotnet-isolated-debug
从PowerShell(之前安装的"Azure Functions Core Tools")启动函数时没有任何问题,然后我可以运行测试,但问题是我需要从测试本身启动函数,这就是测试自动化的理念。
我可以在测试中注入AZ函数类,并临时删除函数参数,以便测试我能够启动它
emailService.Run()
并且它可以工作,我也可以调试,但问题是当参数再次启用时,它会抱怨Run()中缺少"MailMessage email"参数,这是它将从RabbitMQ队列中读取的内容,所以我卡住了...
接下来我可以尝试什么?
编辑1
最后我意识到这很容易,我可以只做Program.main()从测试和它应该只是工作,但问题是这样做我得到下面的异常:
Exception has occurred: CLR/System.InvalidOperationException
An exception of type 'System.InvalidOperationException' occurred in System.Private.CoreLib.dll but was not handled in user code: 'The gRPC channel URI 'http://:50852' could not be parsed.'
1条答案
按热度按时间stszievb1#
我对像这样的集成测试的2分钱。
对于集成测试,我通常更喜欢使用最接近生产的设置。对于Azure功能,最接近的设置是使用Docker容器或部署到Azure。
与其将其作为测试代码的一部分,最好使用一个脚本将该部分外部化,该脚本使用ARM模板部署到Azure,或者运行一个构建的Docker容器(在大多数情况下这要容易得多),然后针对该容器运行测试。
虽然构建自己的主机应该工作,因为Azure功能基本上是这样的,最好我会说它的确定单元测试,如果你需要测试的东西与依赖注入,例如,但对于集成测试,它不够接近生产对我的偏好。