如何在 ASP.Net Core 中正确设置模拟 Request.Form

How to properly set up mock Request.Form in ASP.Net Core

提问人:geoff swartz 提问时间:11/16/2023 更新时间:11/16/2023 访问量:16

问:

我正在尝试创建一个 HttpContextAccessor 模拟类以用于我的控制器单元测试。到目前为止,我有这个。

public class MockHttpContextAccessor
{
    public Mock<IHttpContextAccessor> ContextAccessor { get; private set; }
    public FormCollection RequestForm { get; private set; }
    private FormFileCollection fileCollection;
    
    public MockHttpContextAccessor()
    {
        var requestFeature = new HttpRequestFeature();
        var features = new FeatureCollection();

        features.Set<IHttpRequestFeature>(requestFeature);
        ContextAccessor = new Mock<IHttpContextAccessor>();
        var session = new MockHttpSession();
        var context = new DefaultHttpContext(features);

        fileCollection = new FormFileCollection();
        RequestForm = new FormCollection(new Dictionary<string, StringValues>(), fileCollection);
        
        ContextAccessor.Setup(x => x.HttpContext).Returns(context);
        ContextAccessor.Setup(x => x.HttpContext.Session).Returns(session);
        ContextAccessor.Setup(x => x.HttpContext.Request.Path).Returns("/path");
        ContextAccessor.Setup(x => x.HttpContext.Request.Form).Returns(RequestForm);
        ContextAccessor.Setup(x => x.HttpContext.Request.Form.Files).Returns(RequestForm.Files);
        ContextAccessor.Setup(x => x.HttpContext.Request.Headers).Returns(new Mock<IHeaderDictionary>().Object);
    }

    public void AddFormFieldsOrFile(Dictionary<string, StringValues> fields, List<IFormFile> files = null)
    {
        if (files != null && files.Any())
        {
            ContextAccessor.Object.HttpContext.Request.Headers.Add("Content-Type", "multipart/form-data");
            fileCollection.AddRange(files);
        }

        RequestForm = new FormCollection(fields, fileCollection);
    }
}

public class MockHttpSession : ISession
{
    Dictionary<string, object> sessionStorage = new Dictionary<string, object>();

    public object this[string name]
    {
        get { return sessionStorage[name]; }
        set { sessionStorage[name] = value; }
    }

    string ISession.Id
    {
        get
        {
            throw new NotImplementedException();
        }
    }

    bool ISession.IsAvailable
    {
        get
        {
            throw new NotImplementedException();
        }
    }

    IEnumerable<string> ISession.Keys
    {
        get { return sessionStorage.Keys; }
    }

    void ISession.Clear()
    {
        sessionStorage.Clear();
    }

    void ISession.Remove(string key)
    {
        sessionStorage.Remove(key);
    }

    void ISession.Set(string key, byte[] value)
    {
        sessionStorage[key] = value;
    }

    public Task LoadAsync(CancellationToken cancellationToken = new CancellationToken())
    {
        throw new NotImplementedException();
    }

    public Task CommitAsync(CancellationToken cancellationToken = new CancellationToken())
    {
        throw new NotImplementedException();
    }

    bool ISession.TryGetValue(string key, out byte[] value)
    {
        object storageValue = null;
        if(sessionStorage.TryGetValue(key, out storageValue))
        {
            var bytes = storageValue as byte[];

            if(bytes != null)
            {
                value = bytes;
                return true;
            }

            value = Encoding.UTF8.GetBytes(storageValue.ToString());
            return true;
        }

        value = null;
        return false;
    }        
}

其中大部分工作正常。但是,如果我尝试访问 Request.Form 的值,则其上的 Keys 属性为 null,但是,Files 属性设置正确并且有一个文件。在我的测试设置中,这是我调用的用于设置表单值和文件的代码。

var content = "This is a test file";
var fileName = "test.pdf";
var stream = new MemoryStream();
var writer = new StreamWriter(stream);
writer.Write(content);
writer.Flush();
stream.Position = 0;
IFormFile file = new FormFile(stream, 0, stream.Length, "field_id", fileName);

var formContents = new Dictionary<string, StringValues>()
{
    {"attachment-id", "1"},
    {"prelim", "false"}
};

_httpContextAccessor.AddFormFieldsOrFile(formContents, new List<IFormFile>{ file });
ASP.NET 核心 nunit

评论


答: 暂无答案