c# - 如何在单元测试中验证 Flurl Http 中的请求正文内容?

标签 c# unit-testing flurl

我正在使用 Flurl Http 发出 http 请求。在单元测试中,我试图验证预期的内容是否已传递给发件人。我正在尝试这样的操作:

httpTest.ShouldHaveCalled(url)
        .WithVerb(HttpMethod.Post)
        .WithContentType(contentType)
        .With(w => w.Request.Content.ReadAsStringAsync().Result == content)
        .Times(1);

但是,此操作会失败,并显示 System.ObjectDisposeException 无法访问已释放的对象。对象名称:'System.Net.Http.StringContent'。

看起来 Flurl 在测试中完成验证之前正在处理请求正文内容。如何捕获请求正文进行验证?

编辑(完全可重现的示例):

using System;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;

using Autofac.Extras.Moq;

using Flurl.Http;
using Flurl.Http.Testing;

using Xunit;

namespace XUnitTestProject1
{
    public class MyClassTest : IDisposable
    {
        private readonly AutoMock container;
        private readonly HttpTest client;

        public MyClassTest()
        {
            this.container = AutoMock.GetLoose();
            this.client = new HttpTest();
        }

        [Fact]
        public async Task SendAsync_ValidateRequestBody()
        {
            const string url = "http://www.example.com";
            const string content = "Hello, world";

            var sut = this.container.Create<MyClass>();
            await sut.SendAsync(url, content);

            this.client.ShouldHaveCalled(url)
                .With(w => w.Request.Content.ReadAsStringAsync().Result == content);
        }

        public void Dispose()
        {
            this.container?.Dispose();
            this.client?.Dispose();
        }
    }

    public class MyClass
    {
        public virtual async Task SendAsync(string url, string content)
        {
            await url.PostAsync(new StringContent(content, Encoding.UTF8, "text/plain"));
        }
    }
}

最佳答案

在大多数情况下(请参阅下面的编辑),Furl 已捕获它,您只需以不同的方式访问它即可。

在您的示例中,w.Request 是“原始”HttpRequestMessage ,来自 Flurl 公开的 HttpClient 堆栈,以便您可以在需要时深入了解。 HttpRequestMessage.Content 是一个只读、只进的流,在您访问它时已经被读取和释放。

要断言捕获的字符串主体,您通常只需这样做:

httpTest.ShouldHaveCalled(url)
    ...
    .WithRequestBody(content)

编辑

正如您所指出的,根据您使用 Flurl 的方式,这不起作用。 StringContent 包含的字符串实际上是只写的,即没有属性将其公开以供读取。这就是 Flurl 的 CapturedStringContent 的目的。如果您使用该类型直接替换 StringContentRequestBody 将在您的测试中可用。

文档中没有很好地介绍这一点的原因是,如果您以“Furll 方式”执行操作,那么您首先就不会显式创建内容对象。 PostStringAsync and PostJsonAsync是发送 POST 请求的更常见方法,两者都是使用 CapturedStringContent 实现的。如果可以,请使用其中一种方法,或者如果出于某种原因需要获取较低级别的内容对象,请使用 PostAsync(new CapturedStringContent(...))

关于c# - 如何在单元测试中验证 Flurl Http 中的请求正文内容?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58870297/

相关文章:

c# - 阻止并发集合,例如 ConcurrentBag 或 BlockingCollection

c# - 在 Visual Studio Proff 中调试 native 代码

c# - 使用 Json.Net 反序列化时设置必填字段

angularjs - Angular 单元测试中对其他服务的额外依赖

python - 来自 Django 测试的错误 404?

c# - 在 FlUrl 中,我尝试使用 EnableCookies() 并抛出空引用异常

c# - Nullable int 在 LINQ (C#) 中无法正常工作

java - 在Eclipse中更改单元测试包名称与相应的生产代码包

c# - 从 Flurl.Http v2.0.1 中的请求取回 cookie

c# - 从 Flurl HttpResponseMessage 获取响应正文