可能强制C#Facebook SDK使用HTTP而不是HTTPS?
我需要做一些连接模拟来查看我的代码处理Facebook的各种连接错误。我希望能够模拟500s,超时等。可能强制C#Facebook SDK使用HTTP而不是HTTPS?
最简单的方法是使用Fiddler,但它似乎不能与HTTPS(我尝试时获得403s)一起工作。
其他方法可以强制SDK使用HTTP而不是HTTPS进行调试吗?
Facebook C#SDK支持您的场景模拟整个HttpWebRequest和HttpWebResponse。实际上,我们实际上在单元测试中使用了它,以便Facebook C#SDK中的每一行代码实际上都得到执行并且结果始终相同。 https://github.com/facebook-csharp-sdk/facebook-csharp-sdk/blob/v5/Source/Facebook.Tests/TestExtensions.cs现在您需要在v5分支中检查这些测试,因为我们尚未将这些测试迁移到v6。
对于v5,您需要覆盖FacebookClient中受保护的CreateHttpWebRequest
方法。
下面是没有互联网连接时的v5示例。有三个隐藏类HttpWebRequestWrapper,HttpWebResponseWrapper和WebExceptionWrapper,您将需要使用。
public static void NoInternetConnection(this Mock<Facebook.FacebookClient> facebookClient, out Mock<HttpWebRequestWrapper> mockRequest, out Mock<WebExceptionWrapper> mockWebException)
{
mockRequest = new Mock<HttpWebRequestWrapper>();
mockWebException = new Mock<WebExceptionWrapper>();
var mockAsyncResult = new Mock<IAsyncResult>();
var request = mockRequest.Object;
var webException = mockWebException.Object;
var asyncResult = mockAsyncResult.Object;
mockRequest.SetupProperty(r => r.Method);
mockRequest.SetupProperty(r => r.ContentType);
mockRequest.SetupProperty(r => r.ContentLength);
mockAsyncResult
.Setup(ar => ar.AsyncWaitHandle)
.Returns((ManualResetEvent)null);
mockWebException
.Setup(e => e.GetResponse())
.Returns<HttpWebResponseWrapper>(null);
mockRequest
.Setup(r => r.GetResponse())
.Throws(webException);
mockRequest
.Setup(r => r.EndGetResponse(It.IsAny<IAsyncResult>()))
.Throws(webException);
AsyncCallback callback = null;
mockRequest
.Setup(r => r.BeginGetResponse(It.IsAny<AsyncCallback>(), It.IsAny<object>()))
.Callback<AsyncCallback, object>((c, s) =>
{
callback = c;
})
.Returns(() =>
{
callback(asyncResult);
return asyncResult;
});
var mockRequestCopy = mockRequest;
var mockWebExceptionCopy = mockWebException;
facebookClient.Protected()
.Setup<HttpWebRequestWrapper>("CreateHttpWebRequest", ItExpr.IsAny<Uri>())
.Callback<Uri>(uri =>
{
mockRequestCopy.Setup(r => r.RequestUri).Returns(uri);
mockWebExceptionCopy.Setup(e => e.Message).Returns(string.Format("The remote name could not be resolved: '{0}'", uri.Host));
})
.Returns(request);
}
然后,您可以按如下方式编写测试。
[Fact]
public void SyncWhenThereIsNotInternetConnectionAndFiddlerIsNotOpen_ThrowsWebExceptionWrapper()
{
var mockFb = new Mock<FacebookClient> { CallBase = true };
Mock<HttpWebRequestWrapper> mockRequest;
Mock<WebExceptionWrapper> mockWebException;
mockFb.NoInternetConnection(out mockRequest, out mockWebException);
Exception exception = null;
try
{
var fb = mockFb.Object;
fb.Get(_parameters);
}
catch (Exception ex)
{
exception = ex;
}
mockFb.VerifyCreateHttpWebRequest(Times.Once());
mockRequest.VerifyGetResponse();
mockWebException.VerifyGetReponse();
Assert.IsAssignableFrom<WebExceptionWrapper>(exception);
}
在第6版中,我们嘲笑HttpWebRequest和HttpWebResponse要容易得多。
通过继承HttpWebRequestWrapper
和HttpWebReponseWrapper
来创建您的自定义HttpWebRequest和HttpWebResponse。
然后更改Facebook C#SDK的默认http web请求工厂。这是默认工厂的示例。
FacebookClient.SetDefaultHttpWebRequestFactory(uri => new HttpWebRequestWrapper((HttpWebRequest)WebRequest.Create(uri)));
如果您想要更改每个FacebookClient实例的HttpWebRequestFactor,请使用以下代码。
var fb = new FacebookClient();
fb.HttpWebRequestFactory = uri=> new MyHttpWebRequestWrapper(uri);
注:HttpWebRequestWrapper,HttpWebResponseWrapper,WebExceptionWrapper,FacebookClient.SetDefaultHttpWebRequestFactory和FacebookClient。HttpWebRequestFactory的属性为[EditorBrowsable(EditorBrowsableState.Never)]
,因此您可能无法在智能感知中看到它。
你提到的没有互联网连接的东西实际上应该是facebook c#sdk测试的一部分,而不是你的应用程序单元测试。 sdk应该保证当没有互联网连接时,它总是抛出WebExceptionWrapper,你的应用程序单元测试实际上应该处理WebExceptionWrapper异常,而不是模拟整个httpwebrequest和httpwebresponse。
我建议你为你的代码和代码引入另一个抽象层次,而不是实现。例如。
public interface IFacebookClient {
IEnumerable<Friend> GetFriends();
}
public class HttpsClient : IFacebookClient {
public IEnumerable<Friend> GetFriends() {
// Make a call out to the Facebook API, as per usual
};
}
在你的消费代码中,你会做类似的事情;
public class ConsumingCode {
private IFacebookClient _client;
public ConsumingCode(IFacebookClient client) {
_client = client;
foreach (Friend friend in _client.GetFriends()) {
// Do something with each Friend
}
}
}
如果您使用的是IoC容器,它可以自动为您接线。像Caliburn.Micro这样的MVVM框架也倾向于支持这一点。然后,当涉及到单元测试(或手动测试)时,您可以更改接口的实现;
public class Http403Client : IFacebookClient {
public IEnumerable<Friend> GetFriends() {
throw new HttpException(403, "Forbidden");
}
}
显然,这仅仅是一个实物模型的例子,但我认为它证明了你要实现的概念。
感谢您的回答,但我想测试来自网络的“真实”不良反应。我的代码听起来很合理,我已经用类似于(但更简单)的方法测试了它,而不是你的建议。 Facebook C#库虽然有很多代码,但当它收到错误的HTTP响应时,我需要查看它与代码结合的行为。 – 2012-03-19 06:03:10
在一天结束时,它仍然是你的调用代码响应C#库返回的东西的方式。如果是特定情况 - 当我调用GetFoo()时,在调用HasFoo()之后,发生了一些不好的情况,我需要调用Reset() - 然后将该场景构建到伪装的实现中。您可能希望将传递调用与真实实现结合起来,并根据场景返回固定结果/投入其他人。但是这种交互测试非常适合自动化单元测试。 – MrMDavidson 2012-03-19 06:12:49
再次,谢谢 - 我很欣赏你的建议。但这不是我的问题的答案,我对自动化测试不感兴趣。我需要测试一个我几乎不能控制的组件(C#SDK),我可以做的唯一方法就是进入并向该组件添加代码(这意味着我需要维护我的测试代码放在“生活”组件中,或者使组件对HTTP工作(所以我可以在一次性手动测试中伪造失败)。对于有人会询问自动测试的问题,这是一个很好的建议,但我是对此不感兴趣。 – 2012-03-19 06:18:19
谢谢!这就是我一直在寻找的东西。 – 2012-03-20 03:29:51