gpt4 book ai didi

c# - 如何在 IHttpModules 中测试 HttpApplication 事件

转载 作者:行者123 更新时间:2023-11-30 23:15:40 26 4
gpt4 key购买 nike

我正在编写 HttpModule 并需要对其进行测试,我正在使用 C#.NET4.5.2NUnit起订量

我尝试测试的方法是Context_BeginRequest:

public class XForwardedForRewriter : IHttpModule
{
public void Init(HttpApplication context)
{
context.BeginRequest += Context_BeginRequest;
}

public void Context_BeginRequest(object sender, EventArgs e) { ... }
}

sender 这里是 HttpApplication,这就是问题开始的地方,...可以创建 HttpApplication 的实例,但是无法设置 HttpContext 因为它是只读的并且无法将其传入(通过构造函数或类似的东西)...

我没有 VS2015 Ultimate,也不能使用 Microsoft.Fakes ( Shims ),而 ATM 是唯一的解决方案,我发现 is to create a wrapper 没有这听起来不像是最直接的解决方案....

当我想到这一点时,我确信有人已经遇到过这个确切的问题(因为每次在 TDD 中编写 HttpModule 他都需要模拟 HttpApplication或者做一些解决方法)

如何测试事件 IHttpModules?有模拟 HttpApplication 的方法吗? 最好使用 Moq

编辑:这是我正在尝试测试的代码...它是从 PROXY v2 二进制文件到旧的 X-Forwarded- 的 header 重写器对于...

public class XForwardedForRewriter : IHttpModule
{
public void Dispose()
{
throw new NotImplementedException();
}

byte[] proxyv2HeaderStartRequence = new byte[12] { 0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A };

public void Init(HttpApplication context)
{
context.BeginRequest += Context_BeginRequest;
}

public void Context_BeginRequest(object sender, EventArgs e)
{
var request = ((HttpApplication)sender).Context.Request;

var proxyv2header = request.BinaryRead(12);
if (!proxyv2header.SequenceEqual(proxyv2HeaderStartRequence))
{
request.Abort();
}
else
{
var proxyv2IpvType = request.BinaryRead(5).Skip(1).Take(1).Single();
var isIpv4 = new byte[] { 0x11, 0x12 }.Contains(proxyv2IpvType);
var ipInBinary = isIpv4 ? request.BinaryRead(12) : request.BinaryRead(36);
var ip = Convert.ToString(ipInBinary);

var headers = request.Headers;
Type hdr = headers.GetType();
PropertyInfo ro = hdr.GetProperty("IsReadOnly",
BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.IgnoreCase | BindingFlags.FlattenHierarchy);

ro.SetValue(headers, false, null);

hdr.InvokeMember("InvalidateCachedArrays",
BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance,
null, headers, null);

hdr.InvokeMember("BaseAdd",
BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance,
null, headers,
new object[] { "X-Forwarded-For", new ArrayList { ip } });

ro.SetValue(headers, true, null);
}
}
}

最佳答案

以下显示了使上述案例可测试的潜在解决方法

public class XForwardedForRewriter : IHttpModule {
public void Dispose() {
throw new NotImplementedException();
}

byte[] proxyv2HeaderStartRequence = new byte[12] { 0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A };

public void Init(HttpApplication context) {
context.BeginRequest += Context_BeginRequest;
}

public Func<object, HttpRequestBase> GetRequest = (object sender) => {
return new HttpRequestWrapper(((HttpApplication)sender).Context.Request);
};

public void Context_BeginRequest(object sender, EventArgs e) {
var request = GetRequest(sender);

var proxyv2header = request.BinaryRead(12);
if (!proxyv2header.SequenceEqual(proxyv2HeaderStartRequence)) {
request.Abort();
} else {
var proxyv2IpvType = request.BinaryRead(5).Skip(1).Take(1).Single();
var isIpv4 = new byte[] { 0x11, 0x12 }.Contains(proxyv2IpvType);
var ipInBinary = isIpv4 ? request.BinaryRead(12) : request.BinaryRead(36);
var ip = Convert.ToString(ipInBinary);

var headers = request.Headers;
var hdr = headers.GetType();
var ro = hdr.GetProperty("IsReadOnly",
BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.IgnoreCase | BindingFlags.FlattenHierarchy);

ro.SetValue(headers, false, null);

hdr.InvokeMember("InvalidateCachedArrays",
BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance,
null, headers, null);

hdr.InvokeMember("BaseAdd",
BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance,
null, headers,
new object[] { "X-Forwarded-For", new ArrayList { ip } });

ro.SetValue(headers, true, null);
}
}
}

测试最终会像

[TestClass]
public class XForwardedForRewriterTests {

[TestMethod]
public void Request_Should_Abort() {
//Arrange
var request = Mock.Of<HttpRequestBase>();

var sut = new XForwardedForRewriter();
//replace with mock request for test
sut.GetRequest = (object sender) => request;

//Act
sut.Context_BeginRequest(new object(), EventArgs.Empty);

//Assert
var mockRequest = Mock.Get(request);
mockRequest.Verify(m => m.Abort(), Times.AtLeastOnce);
}


[TestMethod]
public void Request_Should_Forward() {
//Arrange
var request = Mock.Of<HttpRequestBase>();

var mockRequest = Mock.Get(request);
//setup mocked request with desired behavior for test
var proxyv2HeaderStartRequence = new byte[12] { 0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A };
mockRequest
.Setup(m => m.BinaryRead(12))
.Returns(proxyv2HeaderStartRequence);

var fakeProxyv2IpvType = new byte[5] { 0x00, 0x12, 0x00, 0x00, 0x00 };
mockRequest
.Setup(m => m.BinaryRead(5))
.Returns(fakeProxyv2IpvType);

var headers = new NameValueCollection();
mockRequest.Setup(m => m.Headers).Returns(headers);

var sut = new XForwardedForRewriter();
//replace with mock request for test
sut.GetRequest = (object sender) => request;

//Act
sut.Context_BeginRequest(new object(), EventArgs.Empty);

//Assert
//...check request headers
var xForwardedFor = headers["X-Forwarded-For"];
Assert.IsNotNull(xForwardedFor);
}

}

对 Sut 的一个观察是 ip 解析为 "System.Byte[]" 我认为这不是预期的行为。重新检查 proxyv2HeaderStartRequence

除了添加工厂方法来访问请求外,其余被测代码保持不变。观察实际的实现,请求是如何包装在 HttpRequestBase 派生类中的,这允许在其位置交换模拟以进行测试。

现在应该允许在模块中应用 TDD。

关于c# - 如何在 IHttpModules 中测试 HttpApplication 事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42387013/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com