Last active
October 2, 2017 03:50
-
-
Save JayBazuzi/eb5b5fc548d253155ad113ba60898ba8 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class HtmlRequestMessageData | |
{ | |
public readonly string Content; | |
public readonly HttpMethod Method; | |
public readonly Uri RequestUri; | |
[JsonConstructor] | |
HtmlRequestMessageData(HttpMethod method, Uri requestUri, string content) | |
{ | |
this.Method = method; | |
this.RequestUri = requestUri; | |
this.Content = content; | |
} | |
public static async Task<HtmlRequestMessageData> FromHttpRequestMessage(HttpRequestMessage request) | |
{ | |
return new HtmlRequestMessageData(request.Method, request.RequestUri, | |
await (request.Content?.ReadAsStringAsync()).OrDefault()); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class HtmlResponseMessageData | |
{ | |
public readonly string Content; | |
public readonly string ReasonPhrase; | |
public readonly HttpStatusCode StatusCode; | |
[JsonConstructor] | |
public HtmlResponseMessageData(string content, HttpStatusCode statusCode, string reasonPhrase) | |
{ | |
this.Content = content; | |
this.StatusCode = statusCode; | |
this.ReasonPhrase = reasonPhrase; | |
} | |
public static async Task<HtmlResponseMessageData> FromHttpResponseMessage(HttpResponseMessage response) | |
{ | |
return new HtmlResponseMessageData(await (response.Content?.ReadAsStringAsync()).OrDefault(), | |
response.StatusCode, | |
response.ReasonPhrase); | |
} | |
public async Task<HttpResponseMessage> ToHttpResponseMessage() | |
{ | |
return new HttpResponseMessage | |
{ | |
Content = new StringContent(this.Content), | |
ReasonPhrase = this.ReasonPhrase, | |
StatusCode = this.StatusCode | |
}; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[TestClass] | |
public class LiveIntegrationTest : TestBase | |
{ | |
readonly PassthroughAndRecordHttpMessageHandler _recordingHandler = new PassthroughAndRecordHttpMessageHandler(); | |
public TestContext TestContext { get; set; } | |
[TestCleanup] | |
public void TestCleanup() | |
{ | |
var json = JsonConvert.SerializeObject(this._recordingHandler.Recordings, Formatting.Indented); | |
RecordPlaybackTestUtilities.SaveRecordings(TestContext, json); | |
} | |
protected override HttpClientHandler GetHandler() | |
{ | |
return this._recordingHandler; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class PassthroughAndRecordHttpMessageHandler : HttpClientHandler | |
{ | |
public readonly List<Tuple<HtmlRequestMessageData, HtmlResponseMessageData>> Recordings = | |
new List<Tuple<HtmlRequestMessageData, HtmlResponseMessageData>>(); | |
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, | |
CancellationToken cancellationToken) | |
{ | |
var response = await base.SendAsync(request, cancellationToken); | |
await Record(request, response); | |
return response; | |
} | |
async Task Record(HttpRequestMessage request, HttpResponseMessage response) | |
{ | |
this.Recordings.Add(Tuple.Create( | |
await HtmlRequestMessageData.FromHttpRequestMessage(request), | |
await HtmlResponseMessageData.FromHttpResponseMessage(response))); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class PlaybackHtmlMessageHandler : HttpClientHandler | |
{ | |
readonly List<Tuple<HtmlRequestMessageData, HtmlResponseMessageData>> _recordedRequestsAndResponses; | |
int _currentRecordingIndex; | |
public PlaybackHtmlMessageHandler( | |
List<Tuple<HtmlRequestMessageData, HtmlResponseMessageData>> | |
recordedRequestsAndResponses) | |
{ | |
this._recordedRequestsAndResponses = recordedRequestsAndResponses; | |
} | |
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, | |
CancellationToken cancellationToken) | |
{ | |
Tuple<HtmlRequestMessageData, HtmlResponseMessageData> requestAndResponse = | |
this._recordedRequestsAndResponses[this._currentRecordingIndex++]; | |
requestAndResponse.Item1.Should().BeEquivalentTo(await HtmlRequestMessageData.FromHttpRequestMessage(request)); | |
return await requestAndResponse.Item2.ToHttpResponseMessage(); | |
} | |
protected override void Dispose(bool disposing) | |
{ | |
VerifyAllRequestsSent(); | |
base.Dispose(disposing); | |
} | |
public void VerifyAllRequestsSent() | |
{ | |
Assert.AreEqual(this._recordedRequestsAndResponses.Count, this._currentRecordingIndex); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[TestClass] | |
public class PlaybackIntegrationTest : TestBase | |
{ | |
PlaybackHtmlMessageHandler _playbackHandler; | |
public TestContext TestContext { get; set; } | |
[TestInitialize] | |
public void TestInitialize() | |
{ | |
var json = RecordPlaybackTestUtilities.LoadRecordings(TestContext); | |
var recordings = | |
JsonConvert.DeserializeObject<List<Tuple<HtmlRequestMessageData, HtmlResponseMessageData>>>(json); | |
this._playbackHandler = new PlaybackHtmlMessageHandler(recordings); | |
} | |
[TestCleanup] | |
public void TestCleanup() | |
{ | |
this._playbackHandler.VerifyAllRequestsSent(); | |
} | |
protected override HttpClientHandler GetHandler() | |
{ | |
return this._playbackHandler; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
static class RecordPlaybackTestUtilities | |
{ | |
static string GetRecordPath(TestContext testContext) | |
{ | |
var fileName = new StackFrame(skipFrames: 0, fNeedFileInfo: true).GetFileName(); | |
fileName.Should().NotBeNull("File name not found. Check debug info and the like."); | |
var directoryName = Path.GetDirectoryName(fileName); | |
return Path.Combine(directoryName, testContext.TestName + ".record"); | |
} | |
public static void SaveRecordings(TestContext testContext, string json) | |
{ | |
File.WriteAllText(GetRecordPath(testContext), json); | |
} | |
public static string LoadRecordings(TestContext testContext) | |
{ | |
return File.ReadAllText(GetRecordPath(testContext)); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace TaskExtensions | |
{ | |
static class _ | |
{ | |
/// <summary>Turns a null Task into a Task that returns null. For example, <code>await a?.b.OrDefault()</code></summary> | |
/// <remarks>IMO, this is a flaw in C#. It should allow `await null` to return null.</remarks> | |
public static Task<T> OrDefault<T>(this Task<T> task) | |
{ | |
return task ?? Task.FromResult(default(T)); | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public abstract class TestBase | |
{ | |
protected abstract HttpClientHandler GetHandler(); | |
[TestMethod] | |
public async Task GetWeatherByZipCode() | |
{ | |
var httpClient = new HttpClient(GetHandler()); | |
var result = await httpClient.GetStringAsync("http://samples.openweathermap.org/data/2.5/weather?zip=94040,us&appid=b1b15e88fa797225412429c1c50c122a1"); | |
ApprovalTests.Approvals.Verify(result); | |
JsonConvert.DeserializeObject(result).Should().BeEquivalentTo(JsonConvert.DeserializeObject(@"{ | |
""coord"": { | |
""lon"": -122.08, | |
""lat"": 37.39 | |
}, | |
""weather"": [ | |
{ | |
""id"": 500, | |
""main"": ""Rain"", | |
""description"": ""light rain"", | |
""icon"": ""10n"" | |
} | |
], | |
""base"": ""stations"", | |
""main"": { | |
""temp"": 277.14, | |
""pressure"": 1025, | |
""humidity"": 86, | |
""temp_min"": 275.15, | |
""temp_max"": 279.15 | |
}, | |
""visibility"": 16093, | |
""wind"": { | |
""speed"": 1.67, | |
""deg"": 53.0005 | |
}, | |
""clouds"": { ""all"": 1 }, | |
""dt"": 1485788160, | |
""sys"": { | |
""type"": 1, | |
""id"": 471, | |
""message"": 0.0116, | |
""country"": ""US"", | |
""sunrise"": 1485789140, | |
""sunset"": 1485826300 | |
}, | |
""id"": 5375480, | |
""name"": ""Mountain View"", | |
""cod"": 200 | |
}")); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment