Skip to content

Commit 50ebd36

Browse files
authored
Http duration added, XML deserializer for HTTP response content
1 parent e7323f4 commit 50ebd36

File tree

10 files changed

+185
-61
lines changed

10 files changed

+185
-61
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -361,3 +361,4 @@ MigrationBackup/
361361
# Fody - auto-generated XML schema
362362
FodyWeavers.xsd
363363
/src/QAToolKit.Engine.HttpTester.Test/global.json
364+
/.idea/

Directory.Build.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<Project>
22
<PropertyGroup>
3-
<Version>0.2.11</Version>
3+
<Version>0.3.0</Version>
44
</PropertyGroup>
55
</Project>

README.md

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ Get in touch with me on:
1818

1919
A sample on how to easily call the HTTP request with .NET `HttpClient`:
2020

21-
**GET request**
21+
##### GET request
2222
```csharp
2323
using (var client = new HttpTesterClient())
2424
{
@@ -35,12 +35,13 @@ using (var client = new HttpTesterClient())
3535
var expecterResponse = BicycleFixture.GetBicycles().ToExpectedObject();
3636
expecterResponse.ShouldEqual(msg);
3737

38-
Assert.True(client.Duration < 2000);
38+
Assert.True(client.Duration < 2000); //Start() method execution duration
39+
Assert.True(client.HttpDuration < 2000); //HTTP request duration
3940
Assert.True(response.IsSuccessStatusCode);
4041
}
4142
```
4243

43-
**POST request**
44+
##### POST request
4445
```csharp
4546

4647
//Payload object
@@ -74,7 +75,7 @@ using (var client = new HttpTesterClient())
7475
}
7576
```
7677

77-
**POST File Upload request**
78+
##### POST File Upload request
7879

7980
You can upload files with `multipart/form-data` content type like shown below.
8081
There are 2 overloads of `WithMultipart`, one for uploading binary data and the other for string data.
@@ -100,7 +101,31 @@ using (var client = new HttpTesterClient())
100101

101102
There is content-type safety built-in and you can not do `WithMultipart` and `WithJsonBody` in the same request.
102103

103-
**Create Tester client from QAToolKit Swagger request**
104+
##### Deserialize HttpResponse message body
105+
106+
`QAToolKit.Engine.HttpTester` supports 4 `HttpResponse` helper methods to give you maximum flexibility when reading reponse body.
107+
108+
- `GetResponseBodyString`: return response content as a string.
109+
- `GetResponseJsonBody`: deserialize response content from JSON to object
110+
- `GetResponseXmlBody`: deserialize response content from XML to object.
111+
- `GetResponseBodyBytes`: return response content as byte array.
112+
- [Obsolete] `GetResponseBody`: this is obsolete, it deserializes response content from JSON to object. It's replaced by `GetResponseJsonBody`.
113+
114+
##### HttpClient execution time is measured
115+
116+
The library extends `HttpClient` object with `Duration` and `HttpDuration` properties. The first returns the measured duration of `Start();` method and the latter return the duration of HTTP request execution.
117+
118+
```csharp
119+
var response = await client
120+
.CreateHttpRequest(new Uri("https://qatoolkitapi.azurewebsites.net"))
121+
.WithQueryParams(new Dictionary<string, string>() { { "api-version", "1" } })
122+
.Start();
123+
124+
client.Duration; //Start() method execution duration
125+
client.HttpDuration; //HTTP request duration
126+
```
127+
128+
##### Create Tester client from QAToolKit Swagger request
104129

105130
If you are using QAToolKit Swagger library to generate `HttpRequest` object you can use a `CreateHttpRequest` override.
106131

@@ -141,7 +166,7 @@ using (var client = new HttpTesterClient())
141166

142167
Currently `HttpTesterClient` supports:
143168

144-
**Basic authentication**
169+
##### Basic authentication
145170

146171
```csharp
147172
var response = await client
@@ -151,7 +176,7 @@ Currently `HttpTesterClient` supports:
151176
.Start();
152177
```
153178

154-
**Bearer token authentication**
179+
##### Bearer token authentication
155180

156181
```csharp
157182
var response = await client
@@ -161,7 +186,7 @@ Currently `HttpTesterClient` supports:
161186
.Start();
162187
```
163188

164-
**NTLM authentication**
189+
##### NTLM authentication
165190

166191
```csharp
167192
var response = await client
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
namespace QAToolKit.Engine.HttpTester.Test.Fixtures
2+
{
3+
// NOTE: Generated code may require at least .NET Framework 4.5 or .NET Core/Standard 2.0.
4+
/// <remarks/>
5+
[System.SerializableAttribute()]
6+
[System.ComponentModel.DesignerCategoryAttribute("code")]
7+
[System.Xml.Serialization.XmlTypeAttribute(AnonymousType = true)]
8+
[System.Xml.Serialization.XmlRootAttribute(Namespace = "", IsNullable = false)]
9+
public partial class note
10+
{
11+
private string toField;
12+
13+
private string fromField;
14+
15+
private string headingField;
16+
17+
private string bodyField;
18+
19+
/// <remarks/>
20+
public string to
21+
{
22+
get { return this.toField; }
23+
set { this.toField = value; }
24+
}
25+
26+
/// <remarks/>
27+
public string from
28+
{
29+
get { return this.fromField; }
30+
set { this.fromField = value; }
31+
}
32+
33+
/// <remarks/>
34+
public string heading
35+
{
36+
get { return this.headingField; }
37+
set { this.headingField = value; }
38+
}
39+
40+
/// <remarks/>
41+
public string body
42+
{
43+
get { return this.bodyField; }
44+
set { this.bodyField = value; }
45+
}
46+
}
47+
}

src/QAToolKit.Engine.HttpTester.Test/HttpTestAsserterTests.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
using System.Linq;
66
using System.Net;
77
using System.Net.Http;
8+
using System.Runtime.InteropServices;
89
using System.Threading.Tasks;
910
using Xunit;
1011

@@ -114,9 +115,11 @@ public async Task HttpTestAsserterHeaderMissing_Fails()
114115
var asserter = new HttpTestAsserter(response);
115116

116117
var duration = client.Duration;
118+
var httpDuration = client.HttpDuration;
117119
Assert.Throws<ArgumentNullException>(() => asserter
118120
.ResponseContentContains("scott")
119121
.RequestDurationEquals(duration, (x) => x < 2000)
122+
.RequestDurationEquals(httpDuration, (x) => x < 1800)
120123
.ResponseStatusCodeEquals(HttpStatusCode.OK)
121124
.ResponseHasHttpHeader(null)
122125
.AssertAll());
@@ -196,7 +199,7 @@ public async Task HttpTestAsserterDeleteIsBodyEmpty_Success()
196199
var duration = client.Duration;
197200
var assertResults = asserter
198201
.ResponseBodyIsEmpty()
199-
.RequestDurationEquals(duration, (x) => (x > 100 && x < 1000))
202+
.RequestDurationEquals(duration, (x) => (x > 100 && x < 2000))
200203
.ResponseStatusCodeIsSuccess()
201204
.AssertAll();
202205

src/QAToolKit.Engine.HttpTester.Test/HttpTesterClientTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ public async Task HttpTesterClientPostObjectBodyWithFulUrlWithNTLMDefaultAuthori
413413
.WithNTLMAuthentication()
414414
.Start();
415415

416-
var msg = await response.GetResponseBody<dynamic>();
416+
var msg = await response.GetResponseJsonBody<dynamic>();
417417

418418
Assert.True(client.Duration < 2000);
419419
Assert.True(response.IsSuccessStatusCode);

src/QAToolKit.Engine.HttpTester.Test/QAToolKit.Engine.HttpTester.Test.csproj

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,21 +7,21 @@
77
</PropertyGroup>
88

99
<ItemGroup>
10-
<PackageReference Include="coverlet.msbuild" Version="2.9.0">
10+
<PackageReference Include="coverlet.msbuild" Version="3.0.3">
1111
<PrivateAssets>all</PrivateAssets>
1212
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
1313
</PackageReference>
1414
<PackageReference Include="Microsoft.Extensions.Logging" Version="5.0.0" />
1515
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="5.0.0" />
1616
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.8.3" />
1717
<PackageReference Include="QAToolKit.Source.Swagger" Version="0.3.9" />
18-
<PackageReference Include="ExpectedObjects" Version="2.3.6" />
18+
<PackageReference Include="ExpectedObjects" Version="3.5.2" />
1919
<PackageReference Include="xunit" Version="2.4.1" />
2020
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
2121
<PrivateAssets>all</PrivateAssets>
2222
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
2323
</PackageReference>
24-
<PackageReference Include="coverlet.collector" Version="1.3.0">
24+
<PackageReference Include="coverlet.collector" Version="3.0.3">
2525
<PrivateAssets>all</PrivateAssets>
2626
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
2727
</PackageReference>
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
using System;
2+
using System.Net.Http;
3+
using System.Threading.Tasks;
4+
using QAToolKit.Engine.HttpTester.Extensions;
5+
using QAToolKit.Engine.HttpTester.Test.Fixtures;
6+
using Xunit;
7+
8+
namespace QAToolKit.Engine.HttpTester.Test
9+
{
10+
public class XmlDeserializerTests
11+
{
12+
[Fact]
13+
public async Task HttpTesterClientSimple_Success()
14+
{
15+
using (var client = new HttpTesterClient())
16+
{
17+
var response = await client
18+
.CreateHttpRequest(new Uri("https://www.w3schools.com/xml/note.xml"))
19+
.WithMethod(HttpMethod.Get)
20+
.Start();
21+
22+
var msg = await response.GetResponseXmlBody<note>();
23+
24+
Assert.True(client.Duration < 2000);
25+
Assert.True(response.IsSuccessStatusCode);
26+
Assert.Equal("Reminder", msg.heading);
27+
Assert.Equal("Jani", msg.from);
28+
}
29+
}
30+
}
31+
}

src/QAToolKit.Engine.HttpTester/Extensions/HttpResponseMessageExtensions.cs

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
1-
using Newtonsoft.Json;
1+
using System;
2+
using System.IO;
3+
using Newtonsoft.Json;
24
using System.Net.Http;
35
using System.Threading.Tasks;
6+
using System.Xml.Serialization;
47

58
namespace QAToolKit.Engine.HttpTester.Extensions
69
{
@@ -15,11 +18,40 @@ public static class HttpResponseMessageExtensions
1518
/// <typeparam name="T"></typeparam>
1619
/// <param name="httpResponseMessage"></param>
1720
/// <returns></returns>
21+
[Obsolete("This method is obsolete and will be deprecated. Use 'GetResponseJsonBody<T>' instead.")]
1822
public static async Task<T> GetResponseBody<T>(this HttpResponseMessage httpResponseMessage)
1923
{
2024
var bodyResponse = await httpResponseMessage.Content.ReadAsStringAsync();
2125
return JsonConvert.DeserializeObject<T>(bodyResponse);
2226
}
27+
28+
/// <summary>
29+
/// Deserialize JSON response body to object
30+
/// </summary>
31+
/// <param name="httpResponseMessage"></param>
32+
/// <typeparam name="T"></typeparam>
33+
/// <returns></returns>
34+
public static async Task<T> GetResponseJsonBody<T>(this HttpResponseMessage httpResponseMessage)
35+
{
36+
var bodyResponse = await httpResponseMessage.Content.ReadAsStringAsync();
37+
return JsonConvert.DeserializeObject<T>(bodyResponse);
38+
}
39+
40+
/// <summary>
41+
/// Deserialize XML response body to object
42+
/// </summary>
43+
/// <param name="httpResponseMessage"></param>
44+
/// <typeparam name="T"></typeparam>
45+
/// <returns></returns>
46+
public static async Task<T> GetResponseXmlBody<T>(this HttpResponseMessage httpResponseMessage)
47+
{
48+
var bodyResponse = await httpResponseMessage.Content.ReadAsStringAsync();
49+
var xmlSerialize = new XmlSerializer(typeof(T));
50+
51+
var xmlResult = (T)xmlSerialize.Deserialize(new StringReader(bodyResponse));
52+
53+
return xmlResult ?? default(T);
54+
}
2355

2456
/// <summary>
2557
/// Get response as string

0 commit comments

Comments
 (0)