Skip to content

Commit 877f973

Browse files
authored
v5.4.5 (#88)
- *Fixed:* Added `TesterBase.JsonMediaTypeNames` which provides a list of valid JSON media types to be used to determine JSON-related payloads in tests. - *Fixed:* Added Xunit `ApiTestFixture.OnConfiguration` to enable configuration to be perform prior to test execution.
1 parent 4b73b94 commit 877f973

File tree

9 files changed

+64
-34
lines changed

9 files changed

+64
-34
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
Represents the **NuGet** versions.
44

5+
## v5.4.5
6+
- *Fixed:* Added `TesterBase.JsonMediaTypeNames` which provides a list of valid JSON media types to be used to determine JSON-related payloads in tests.
7+
- *Fixed:* Added Xunit `ApiTestFixture.OnConfiguration` to enable configuration to be perform prior to test execution.
8+
59
## v5.4.4
610
- *Fixed:* The `XunitLocalTestImplementor.SetLocalImplementor` has been made public.
711
- *Fixed:* Added `TesterBase.ReplaceTestFrameworkImplementor` to enable dynamic replacement.

Common.targets

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<Project>
22
<PropertyGroup>
3-
<Version>5.4.4</Version>
3+
<Version>5.4.5</Version>
44
<LangVersion>preview</LangVersion>
55
<Authors>Avanade</Authors>
66
<Company>Avanade</Company>

src/UnitTestEx.Xunit/ApiTestFixture.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,16 @@ public class ApiTestFixture<TEntryPoint> : IDisposable where TEntryPoint : class
1515
private ApiTester<TEntryPoint>? _apiTester = ApiTester.Create<TEntryPoint>(() => new XunitLocalTestImplementor());
1616
private bool _disposed;
1717

18+
/// <summary>
19+
/// Initializes a new instance of the <see cref="ApiTestFixture{TEntryPoint}"/> class.
20+
/// </summary>
21+
public ApiTestFixture() => OnConfiguration();
22+
23+
/// <summary>
24+
/// Provides an opportunity to perform initial <see cref="Test"/> configuration before use.
25+
/// </summary>
26+
protected virtual void OnConfiguration() { }
27+
1828
/// <summary>
1929
/// Gets the shared <see cref="ApiTester{TEntryPoint}"/> for testing.
2030
/// </summary>

src/UnitTestEx/Abstractions/TesterBase.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ static TesterBase()
5151
}
5252
}
5353

54+
/// <summary>
55+
/// Gets the default JSON media type names used for JSON serialization/deserialization.
56+
/// </summary>
57+
public static string[] JsonMediaTypeNames { get; set; } = [MediaTypeNames.Application.Json, "application/json-patch+json", "application/problem+json", "application/merge-patch+json"];
58+
5459
/// <summary>
5560
/// Initializes a new instance of the <see cref="TesterBase"/> class.
5661
/// </summary>
@@ -248,7 +253,7 @@ internal void LogHttpResponseMessage(HttpResponseMessage res, Stopwatch? sw)
248253

249254
object? jo = null;
250255
var content = res.Content.ReadAsStringAsync().GetAwaiter().GetResult();
251-
if (!string.IsNullOrEmpty(content) && res.Content?.Headers?.ContentType?.MediaType == MediaTypeNames.Application.Json)
256+
if (!string.IsNullOrEmpty(content) && JsonMediaTypeNames.Contains(res.Content?.Headers?.ContentType?.MediaType))
252257
{
253258
try
254259
{

src/UnitTestEx/Assertors/ActionResultAssertor.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
using System.Diagnostics;
1010
using System.Diagnostics.CodeAnalysis;
1111
using System.IO;
12+
using System.Linq;
1213
using System.Net;
1314
using System.Net.Http;
1415
using System.Net.Mime;
@@ -332,7 +333,7 @@ internal ActionResultAssertor AssertContentResult<TValue>(TValue expectedValue,
332333
AssertResultType<ContentResult>();
333334

334335
var cr = (ContentResult)Result;
335-
if (expectedValue != null && cr.Content != null && cr.ContentType == MediaTypeNames.Application.Json)
336+
if (expectedValue != null && cr.Content != null && TesterBase.JsonMediaTypeNames.Contains(cr.ContentType))
336337
return AssertValue(expectedValue, JsonSerializer.Deserialize<TValue>(cr.Content)!, pathsToIgnore);
337338
else
338339
return AssertValue(expectedValue, cr.Content!, pathsToIgnore);

src/UnitTestEx/Assertors/HttpResponseMessageAssertor.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
using Microsoft.Net.Http.Headers;
44
using System;
5+
using System.Linq;
56
using System.Net.Http;
67
using System.Net.Mime;
78
using UnitTestEx.Abstractions;
@@ -79,7 +80,7 @@ public HttpResponseMessageAssertor AssertValue<TValue>(TValue? expectedValue, pa
7980
return this;
8081
}
8182

82-
if (Response.Content.Headers?.ContentType?.MediaType == MediaTypeNames.Application.Json)
83+
if (TesterBase.JsonMediaTypeNames.Contains(Response.Content.Headers?.ContentType?.MediaType))
8384
{
8485
var json = Response.Content.ReadAsStringAsync().GetAwaiter().GetResult();
8586
if (expectedValue == null)

src/UnitTestEx/Mocking/MockHttpClientRequest.cs

Lines changed: 19 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -186,35 +186,26 @@ private bool RequestPredicate(HttpRequestMessage request)
186186

187187
var body = request.Content!.ReadAsStringAsync().GetAwaiter().GetResult();
188188

189-
switch (_mediaType.ToLowerInvariant())
189+
if (TesterBase.JsonMediaTypeNames.Contains(_mediaType.ToLowerInvariant()))
190190
{
191-
// Deserialize the JSON and compare.
192-
case MediaTypeNames.Application.Json:
193-
try
194-
{
195-
var content = _content is string cstring ? cstring : JsonSerializer.Serialize(_content);
196-
var options = JsonComparerOptions.Clone();
197-
options.JsonSerializer ??= JsonSerializer;
198-
var jcr = new JsonElementComparer(options).Compare(content, body, _pathsToIgnore);
199-
if (jcr.HasDifferences && _traceRequestComparisons)
200-
Implementor.WriteLine($"UnitTestEx > Mismatched HTTP request {request.Method} {request.RequestUri} mocked vs actual trace comparison differences:{Environment.NewLine}{jcr}");
201-
202-
return jcr.AreEqual;
203-
}
204-
catch
205-
{
206-
return false;
207-
}
208-
209-
// For any other content type, just compare the body.
210-
case MediaTypeNames.Text.Plain:
211-
case MediaTypeNames.Text.Xml:
212-
case MediaTypeNames.Text.Html:
213-
case MediaTypeNames.Application.Soap:
214-
case MediaTypeNames.Application.Xml:
215-
default:
216-
return body == _content?.ToString();
191+
try
192+
{
193+
var content = _content is string cstring ? cstring : JsonSerializer.Serialize(_content);
194+
var options = JsonComparerOptions.Clone();
195+
options.JsonSerializer ??= JsonSerializer;
196+
var jcr = new JsonElementComparer(options).Compare(content, body, _pathsToIgnore);
197+
if (jcr.HasDifferences && _traceRequestComparisons)
198+
Implementor.WriteLine($"UnitTestEx > Mismatched HTTP request {request.Method} {request.RequestUri} mocked vs actual trace comparison differences:{Environment.NewLine}{jcr}");
199+
200+
return jcr.AreEqual;
201+
}
202+
catch
203+
{
204+
return false;
205+
}
217206
}
207+
else
208+
return body == _content?.ToString();
218209
}
219210

220211
/// <inheritdoc/>
@@ -235,7 +226,7 @@ public override string ToString()
235226
if (_content == null)
236227
return "'No content'";
237228

238-
if (_mediaType?.ToLowerInvariant() == MediaTypeNames.Application.Json && _content is not string)
229+
if (TesterBase.JsonMediaTypeNames.Contains(_mediaType?.ToLowerInvariant()) && _content is not string)
239230
return JsonSerializer.Serialize(_content);
240231

241232
return _content.ToString();
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
using System;
2+
3+
namespace UnitTestEx.Xunit.Test
4+
{
5+
public class ProductApiTestFixture<TStartup> : ApiTestFixture<TStartup> where TStartup : class
6+
{
7+
private static int _counter = 0;
8+
9+
protected override void OnConfiguration()
10+
{
11+
_counter++;
12+
if (_counter > 1)
13+
{
14+
throw new InvalidOperationException("ProductApiTestFixture should only be instantiated once per test run.");
15+
}
16+
}
17+
}
18+
}

tests/UnitTestEx.Xunit.Test/ProductControllerTest.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,9 @@
1010

1111
namespace UnitTestEx.Xunit.Test
1212
{
13-
public class ProductControllerTest : WithApiTester<Startup>
13+
public class ProductControllerTest : WithApiTester<Startup>, IClassFixture<ProductApiTestFixture<Startup>>
1414
{
15-
public ProductControllerTest(ApiTestFixture<Startup> fixture, ITestOutputHelper output) : base(fixture, output) { }
15+
public ProductControllerTest(ProductApiTestFixture<Startup> fixture, ITestOutputHelper output) : base(fixture, output) { }
1616

1717
[Fact]
1818
public void Notfound()

0 commit comments

Comments
 (0)