Azure函数(AF)3.0/.NET 5.0/XUnit单元测试-编译错误(C#)



我正在尝试调整AF 3.0/.NET Core 3.1/xUnit的Microsoft示例(请参阅在Azure函数中测试代码的策略(,以使用AF 3.0/.NET5.0/xUnit。但是,我遇到了编译问题。

Azure函数是一个简单的HTTP触发器(仅限GET(,ExportFuncApp.csproj文件如下:

<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
<AzureFunctionsVersion>v3</AzureFunctionsVersion>
<OutputType>Exe</OutputType>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.0.12" />
<PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.2.0" OutputItemType="Analyzer" />
<PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.5.2" />
</ItemGroup>
<ItemGroup>
<None Update="host.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
<None Update="local.settings.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
<CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>
</ItemGroup>
</Project>

ExportFunc.cs文件如下:

using System.Net;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Extensions.Logging;
namespace ExportFuncApp
{
public class ExportFunc
{
[Function(nameof(ExportFunc))]
public static HttpResponseData Run([HttpTrigger(AuthorizationLevel.Function, "get")] HttpRequestData req,
FunctionContext executionContext)
{
var logger = executionContext.GetLogger("ExportFunc");
logger.LogInformation("C# HTTP trigger function processed a request.");
var response = req.CreateResponse(HttpStatusCode.OK);
response.Headers.Add("Content-Type", "text/plain; charset=utf-8");
response.WriteString("Welcome to Azure Functions!");
return response;
}
}
}

没有什么特别的。但是,Microsoft(.NET Core 3.1(提供的XUnit测试并不真正适用于.NET 5.0。有一篇关于StackOverflow的文章:在.NET5中测试Azure函数。文中给出了4种解决方案,它们都存在编译问题。给出的第一个解决方案是(ExportFuncUnitTests2.cs(:

using Xunit;
using ExportFuncApp;
using System.Threading.Tasks;
using System.IO;
using System.Text;
using Moq;
using Microsoft.Azure.Functions.Worker;
using System.Net;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Microsoft.Azure.Functions.Worker.Http;
namespace ExportFuncAppUnitTestsXunit
{
public class ExportFuncUnitTests2
{
[Fact]
public async Task Http_trigger_should_return_known_string()
{
var serviceCollection = new ServiceCollection();
serviceCollection.AddScoped<ILoggerFactory, LoggerFactory>();
var serviceProvider = serviceCollection.BuildServiceProvider();
var context = new Mock<FunctionContext>();
context.SetupProperty(c => c.InstanceServices, serviceProvider);
var byteArray = Encoding.ASCII.GetBytes("test");
var bodyStream = new MemoryStream(byteArray);
var request = new Mock<HttpRequestData>(context.Object);
request.Setup(r => r.Body).Returns(bodyStream);
request.Setup(r => r.CreateResponse()).Returns(() =>
{
var response = new Mock<HttpResponseData>(context.Object);
response.SetupProperty(r => r.Headers, new HttpHeadersCollection());
response.SetupProperty(r => r.StatusCode);
response.SetupProperty(r => r.Body, new MemoryStream());
return response.Object;
});
var result = await ExportFunc.Run(request.Object, context.Object);
result.HttpResponse.Body.Seek(0, SeekOrigin.Begin);
// Assert
var reader = new StreamReader(result.HttpResponse.Body);
var responseBody = await reader.ReadToEndAsync();
Assert.NotNull(result);
Assert.Equal(HttpStatusCode.OK, result.HttpResponse.StatusCode);
Assert.Equal("Hello test", responseBody);
}
}
}

这导致ExportFuncUnitTests2.cs:中出现编译错误

CS1061  'HttpResponseData' does not contain a definition for 'GetAwaiter' and no accessible extension method 'GetAwaiter' accepting a first argument of type 'HttpResponseData' could be found (are you missing a using directive or an assembly reference?)
for:
var result = await ExportFunc.Run(request.Object, context.Object);

文章中给出的第二个解决方案涉及FakeHttpRequestData.cs:

using System;
using System.Collections.Generic;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Azure.Functions.Worker;
using System.IO;
using System.Security.Claims;
namespace ExportFuncAppUnitTestsXunit
{
class FakeHttpRequestData : HttpRequestData
{
public FakeHttpRequestData(FunctionContext functionContext, Uri url, Stream body = null) : base(functionContext)
{
Url = url;
Body = body ?? new MemoryStream();
}
public override Stream Body { get; } = new MemoryStream();
public override HttpHeadersCollection Headers { get; } = new HttpHeadersCollection();
public override IReadOnlyCollection<IHttpCookie> Cookies { get; }
public override Uri Url { get; }
public override IEnumerable<ClaimsIdentity> Identities { get; }
public override string Method { get; }
public override HttpResponseData CreateResponse()
{
return new FakeHttpResponseData(FunctionContext);
}
}
}

和,FakeHttpResponseData.cs:

using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Azure.Functions.Worker;
using System.Net;
using System.IO;
namespace ExportFuncAppUnitTestsXunit
{
class FakeHttpResponseData : HttpResponseData
{
public FakeHttpResponseData(FunctionContext functionContext) : base(functionContext)
{
}
public override HttpStatusCode StatusCode { get; set; }
public override HttpHeadersCollection Headers { get; set; } = new HttpHeadersCollection();
public override Stream Body { get; set; } = new MemoryStream();
public override HttpCookies Cookies { get; }
}
}

测试是(ExportFuncUnitTests2.cs(:

using Xunit;
using ExportFuncApp;
using System.Threading.Tasks;
using System.IO;
using System.Text;
using Moq;
using Microsoft.Azure.Functions.Worker;
using System;
using System.Net;
using Microsoft.Extensions.Logging.Abstractions;
namespace ExportFuncAppUnitTestsXunit
{
public class ExportFuncUnitTests2
{
[Fact]
public async Task Http_trigger_should_return_known_string()
{
// Arrange
var body = new MemoryStream(Encoding.ASCII.GetBytes("{ "test": true }"));
var context = new Mock<FunctionContext>();
var request = new FakeHttpRequestData(
context.Object,
new Uri("https://stackoverflow.com"),
body);
// Act
var function = new ExportFunc(new NullLogger<ExportFunc>());
var result = await function.Run(request, context);
result.HttpResponse.Body.Position = 0;
// Assert
var reader = new StreamReader(result.HttpResponse.Body);
var responseBody = await reader.ReadToEndAsync();
Assert.NotNull(result);
Assert.Equal(HttpStatusCode.OK, result.HttpResponse.StatusCode);
Assert.Equal("Hello test", responseBody);
}
}
}

ExportFuncUnitTests2.cs存在以下编译错误:

CS1729  'ExportFunc' does not contain a constructor that takes 1 arguments
for:
var function = new ExportFunc(new NullLogger<ExportFunc>());

CS1503  Argument 2: cannot convert from 'Moq.Mock<Microsoft.Azure.Functions.Worker.FunctionContext>' to 'Microsoft.Azure.Functions.Worker.FunctionContext'
for:
var result = await function.Run(request, context);

我的文章《在独立进程中运行C#Azure函数指南》有些有用,但在单元测试方面没有帮助。也许我没有抓住重点。由于没有关于如何使用Microsoft的.NET 5.0对AF 3.0进行单元测试的示例/文档,那么我不应该尝试这样做吗?

任何指示都将不胜感激。谢谢

ExportFunc中的Run()函数不可用。因此,您应该更换线路:

var result = await function.Run(request, context)

带有:

var result = function.Run(request, context).

如果你想测试一个不可用的函数(即async Run()(,那么你可以用await从单元测试中调用它。

最新更新