You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Azure Function单元测试:HttpRequest未触发System.NotSupportedException

解决方案

要让测试中的HttpRequest行为贴近Azure Functions生产环境,核心是模拟不支持Length属性的请求体流——生产环境中Azure Functions使用的HttpRequestStream本身就会在访问Length时抛出System.NotSupportedException,而你之前用的普通流(如MemoryStream)或DefaultHttpContext的默认流都支持Length,所以不会触发异常。

方法1:自定义不支持Length的流

编写一个继承自Stream的自定义流,重写必要方法并在访问Length时抛出异常:

public class UnsupportedLengthStream : Stream
{
    private readonly Stream _innerStream;

    public UnsupportedLengthStream(Stream innerStream)
    {
        _innerStream = innerStream;
    }

    public override bool CanRead => _innerStream.CanRead;
    public override bool CanSeek => _innerStream.CanSeek;
    public override bool CanWrite => _innerStream.CanWrite;
    // 关键:访问Length时抛出异常
    public override long Length => throw new NotSupportedException("Stream does not support seeking.");
    public override long Position { get => _innerStream.Position; set => _innerStream.Position = value; }

    public override void Flush() => _innerStream.Flush();
    public override int Read(byte[] buffer, int offset, int count) => _innerStream.Read(buffer, offset, count);
    public override long Seek(long offset, SeekOrigin origin) => _innerStream.Seek(offset, origin);
    public override void SetLength(long value) => _innerStream.SetLength(value);
    public override void Write(byte[] buffer, int offset, int count) => _innerStream.Write(buffer, offset, count);
    public override async Task<int> ReadAsync(byte[] buffer, int offset, int count, CancellationToken cancellationToken)
        => await _innerStream.ReadAsync(buffer, offset, count, cancellationToken);
}

方法2:在测试中配置模拟的HttpRequest

用NSubstitute将自定义流注入到模拟的HttpRequest中,替代默认的支持Length的流:

[TestClass]
public class FunctionTests
{
    [TestMethod]
    public async Task WhenAccessingBodyLength_ThrowsNotSupportedException()
    {
        // 1. 创建测试用的请求体内容
        var content = new StringContent("test body");
        var innerStream = await content.ReadAsStreamAsync();
        
        // 2. 用自定义流包装内部流
        var unsupportedStream = new UnsupportedLengthStream(innerStream);
        
        // 3. 模拟HttpRequest,设置Body为自定义流
        var req = Substitute.For<HttpRequest>();
        req.Body.Returns(unsupportedStream);
        
        // 4. 模拟FunctionContext(按你之前的配置即可)
        var context = Substitute.For<FunctionContext>();
        
        // 5. 调用函数并验证异常
        var function = new YourFunctionClass();
        await Assert.ThrowsExceptionAsync<NotSupportedException>(() => function.Run(req, context));
    }
}

补充说明

  • 不要使用DefaultHttpContext().Request:它的默认Body是MemoryStream,天然支持Length属性,无法模拟生产环境的行为。
  • 异步调用不影响异常触发:异常是在访问Length属性时抛出,和调用方式同步/异步无关,核心还是流的类型。

内容的提问来源于stack exchange,提问作者user71030

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 18:15:01