Skip to content

Commit af6499a

Browse files
committed
Implemented TestBase.AssertJsonResponse
1 parent 6d7cff5 commit af6499a

2 files changed

Lines changed: 51 additions & 31 deletions

File tree

src/Dibix.Testing/Http/WebApiTestBase.cs

Lines changed: 2 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,11 @@
11
using System;
22
using System.Linq.Expressions;
33
using System.Net.Http;
4-
using System.Text.RegularExpressions;
54
using System.Threading.Tasks;
65
using Dibix.Http.Client;
76
using Dibix.Testing.Data;
87
using Microsoft.Extensions.DependencyInjection;
98
using Newtonsoft.Json;
10-
using Newtonsoft.Json.Linq;
11-
using Newtonsoft.Json.Serialization;
129

1310
namespace Dibix.Testing.Http
1411
{
@@ -55,13 +52,13 @@ protected async Task<TResponseContent> InvokeApi<TService, TResponseContent>(TSe
5552
protected async Task<TResponseContent> InvokeApiAndAssertResponse<TService, TResponseContent>(TService service, Expression<Func<TService, Task<HttpResponse<TResponseContent>>>> methodSelector, string expectedText = null, string outputName = null, Action<JsonSerializerSettings> configureSerializer = null)
5653
{
5754
HttpResponse<TResponseContent> response = await InvokeApiCore(service, methodSelector).ConfigureAwait(false);
58-
Assert(response, expectedText, outputName, configureSerializer);
55+
AssertJsonResponse(response.ResponseContent, configureSerializer, outputName, expectedText);
5956
return response.ResponseContent;
6057
}
6158
protected async Task<TResponseContent> InvokeApiAndAssertResponse<TService, TResponseContent>(HttpTestContext context, Expression<Func<TService, Task<HttpResponse<TResponseContent>>>> methodSelector, string expectedText = null, string outputName = null, Action<JsonSerializerSettings> configureSerializer = null)
6259
{
6360
HttpResponse<TResponseContent> response = await CreateServiceAndInvokeApi(context, methodSelector).ConfigureAwait(false);
64-
Assert(response, expectedText, outputName, configureSerializer);
61+
AssertJsonResponse(response.ResponseContent, configureSerializer, outputName, expectedText);
6562
return response.ResponseContent;
6663
}
6764

@@ -85,32 +82,6 @@ private static Task<TResponse> CreateServiceAndInvokeApi<TService, TResponse>(Ht
8582
return InvokeApiCore(service, methodSelector);
8683
}
8784

88-
private void Assert<TResponseContent>(HttpResponse<TResponseContent> response, string expectedText, string outputName, Action<JsonSerializerSettings> configureSerializer)
89-
{
90-
JsonSerializerSettings settings = new JsonSerializerSettings
91-
{
92-
ContractResolver = new DefaultContractResolver { NamingStrategy = new CamelCaseNamingStrategy() },
93-
Formatting = Formatting.Indented,
94-
DateTimeZoneHandling = DateTimeZoneHandling.Unspecified
95-
};
96-
configureSerializer?.Invoke(settings);
97-
98-
const string extension = "json";
99-
string outputNameResolved = outputName ?? TestContext.TestName;
100-
string expectedTextResolved = expectedText ?? GetEmbeddedResourceContent($"{outputNameResolved}.{extension}");
101-
string actualText = JsonConvert.SerializeObject(response.ResponseContent, settings);
102-
JToken actualTextDom = JToken.Parse(actualText);
103-
string expectedTextReplaced = Regex.Replace(expectedTextResolved, @"\{(?<path>[A-Za-z.]+)\}", x =>
104-
{
105-
string path = x.Groups["path"].Value;
106-
if (!(actualTextDom.SelectToken(path) is JValue value) || value.Value == null)
107-
throw new InvalidOperationException($"Replace pattern did not match a JSON path in the actual document: {path} ({x.Index})");
108-
109-
return value.Value.ToString();
110-
});
111-
AssertEqual(expectedTextReplaced, actualText, outputNameResolved, extension: extension);
112-
}
113-
11485
private static HttpTestContext CreateTestContext(IHttpClientFactory httpClientFactory, HttpClientOptions httpClientOptions, IHttpAuthorizationProvider authorizationProvider)
11586
{
11687
return new HttpTestContext(httpClientFactory, httpClientOptions, authorizationProvider);

src/Dibix.Testing/TestBase.cs

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,15 @@
44
using System.Linq;
55
using System.Reflection;
66
using System.Runtime.CompilerServices;
7+
using System.Text;
8+
using System.Text.RegularExpressions;
79
using System.Threading;
810
using System.Threading.Tasks;
911
using Dibix.Testing.Configuration;
1012
using Microsoft.VisualStudio.TestTools.UnitTesting;
1113
using Newtonsoft.Json;
14+
using Newtonsoft.Json.Linq;
15+
using Newtonsoft.Json.Serialization;
1216

1317
namespace Dibix.Testing
1418
{
@@ -119,6 +123,51 @@ protected void AssertEqual(string expected, string actual, string outputName, st
119123
throw new AssertTextFailedException(expectedNormalized, actualNormalized, message);
120124
}
121125

126+
protected void AssertJsonResponse<T>(T response, Action<JsonSerializerSettings> configureSerializer = null, string outputName = null, string expectedText = null)
127+
{
128+
JsonSerializerSettings settings = new JsonSerializerSettings
129+
{
130+
ContractResolver = new DefaultContractResolver { NamingStrategy = new CamelCaseNamingStrategy() },
131+
Formatting = Formatting.Indented,
132+
DateTimeZoneHandling = DateTimeZoneHandling.Unspecified
133+
};
134+
configureSerializer?.Invoke(settings);
135+
136+
const string extension = "json";
137+
string outputNameResolved = outputName ?? TestContext.TestName;
138+
string expectedTextResolved = expectedText ?? GetEmbeddedResourceContent($"{outputNameResolved}.{extension}");
139+
string actualText = JsonConvert.SerializeObject(response, settings);
140+
JToken actualTextDom = JToken.Parse(actualText);
141+
142+
// Replace JSON path placeholders in the expected text with values from the actual text
143+
// This is useful for undeterministic values like IDs
144+
// Example:
145+
// {
146+
// "values": [
147+
// {
148+
// "id": "{values[0].id}"
149+
// }
150+
// ]
151+
// }
152+
string expectedTextReplaced = Regex.Replace(expectedTextResolved, """
153+
"{(?<path>([A-Za-z]+(\[[\d]+\])?)(\.([A-Za-z]+(\[[\d]+\])?)){0,})\}"
154+
""", x =>
155+
{
156+
string path = x.Groups["path"].Value;
157+
if (actualTextDom.SelectToken(path) is not JValue jsonValue || jsonValue.Value == null)
158+
throw new InvalidOperationException($"Replace pattern did not match a JSON path in the actual document: {path} ({x.Index})");
159+
160+
StringBuilder sb = new StringBuilder();
161+
using TextWriter textWriter = new StringWriter(sb);
162+
using JsonWriter writer = new JsonTextWriter(textWriter);
163+
jsonValue.WriteTo(writer);
164+
string replacement = sb.ToString();
165+
return replacement;
166+
});
167+
168+
AssertEqual(expectedTextReplaced, actualText, outputNameResolved, extension: extension);
169+
}
170+
122171
protected void LogException(Exception exception) => TestResultFileManager.AddTestFile("AdditionalErrors.txt", $@"An error occured while collecting the last event log errors
123172
{exception}");
124173

0 commit comments

Comments
 (0)