Skip to content

Commit 8756f25

Browse files
author
Bart Koelman
committed
Fixed assertions on DateTime/DateTimeOffset in tests
1 parent 7057c89 commit 8756f25

File tree

9 files changed

+44
-31
lines changed

9 files changed

+44
-31
lines changed
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
using Newtonsoft.Json;
2+
3+
namespace JsonApiDotNetCoreExampleTests
4+
{
5+
internal static class IntegrationTestConfiguration
6+
{
7+
// Because our tests often deserialize incoming responses into weakly-typed string-to-object dictionaries (as part of ResourceObject),
8+
// Newtonsoft.JSON is unable to infer the target type in such cases. So we steer a bit using explicit configuration.
9+
public static readonly JsonSerializerSettings DeserializationSettings = new JsonSerializerSettings
10+
{
11+
// Choosing between DateTime and DateTimeOffset is impossible: it depends on how the resource properties are declared.
12+
// So instead we leave them as strings and let the test itself deal with the conversion.
13+
DateParseHandling = DateParseHandling.None,
14+
15+
// Here we must choose between double (default) and decimal. Favored decimal because it has higher precision (but lower range).
16+
FloatParseHandling = FloatParseHandling.Decimal
17+
};
18+
}
19+
}

test/JsonApiDotNetCoreExampleTests/IntegrationTestContext.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -189,7 +189,8 @@ private TResponseDocument DeserializeResponse<TResponseDocument>(string response
189189

190190
try
191191
{
192-
return JsonConvert.DeserializeObject<TResponseDocument>(responseText);
192+
return JsonConvert.DeserializeObject<TResponseDocument>(responseText,
193+
IntegrationTestConfiguration.DeserializationSettings);
193194
}
194195
catch (JsonException exception)
195196
{

test/JsonApiDotNetCoreExampleTests/IntegrationTests/Filtering/FilterDataTypeTests.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
using System.Net;
33
using System.Threading.Tasks;
44
using FluentAssertions;
5+
using FluentAssertions.Common;
56
using FluentAssertions.Extensions;
67
using Humanizer;
78
using JsonApiDotNetCore.Configuration;
@@ -138,7 +139,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
138139
httpResponse.Should().HaveStatusCode(HttpStatusCode.OK);
139140

140141
responseDocument.ManyData.Should().HaveCount(1);
141-
responseDocument.ManyData[0].Attributes["someDateTime"].Should().Be(resource.SomeDateTime);
142+
responseDocument.ManyData[0].Attributes["someDateTime"].Should().BeCloseTo(resource.SomeDateTime);
142143
}
143144

144145
[Fact]
@@ -147,7 +148,7 @@ public async Task Can_filter_equality_on_type_DateTimeOffset()
147148
// Arrange
148149
var resource = new FilterableResource
149150
{
150-
SomeDateTimeOffset = new DateTimeOffset(27.January(2003).At(11, 22, 33, 44), TimeSpan.FromHours(3))
151+
SomeDateTimeOffset = 27.January(2003).At(11, 22, 33, 44).ToDateTimeOffset(TimeSpan.FromHours(3))
151152
};
152153

153154
await _testContext.RunOnDatabaseAsync(async dbContext =>
@@ -167,7 +168,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
167168
httpResponse.Should().HaveStatusCode(HttpStatusCode.OK);
168169

169170
responseDocument.ManyData.Should().HaveCount(1);
170-
responseDocument.ManyData[0].Attributes["someDateTimeOffset"].Should().Be(resource.SomeDateTimeOffset.LocalDateTime);
171+
responseDocument.ManyData[0].Attributes["someDateTimeOffset"].Should().BeCloseTo(resource.SomeDateTimeOffset);
171172
}
172173

173174
[Fact]
@@ -254,7 +255,7 @@ public async Task Can_filter_is_null_on_type(string propertyName)
254255
SomeNullableDouble = 1,
255256
SomeNullableGuid = Guid.NewGuid(),
256257
SomeNullableDateTime = 1.January(2001),
257-
SomeNullableDateTimeOffset = 1.January(2001),
258+
SomeNullableDateTimeOffset = 1.January(2001).ToDateTimeOffset(TimeSpan.FromHours(-1)),
258259
SomeNullableTimeSpan = TimeSpan.FromHours(1),
259260
SomeNullableEnum = DayOfWeek.Friday
260261
};
@@ -305,7 +306,7 @@ public async Task Can_filter_is_not_null_on_type(string propertyName)
305306
SomeNullableDouble = 1,
306307
SomeNullableGuid = Guid.NewGuid(),
307308
SomeNullableDateTime = 1.January(2001),
308-
SomeNullableDateTimeOffset = 1.January(2001),
309+
SomeNullableDateTimeOffset = 1.January(2001).ToDateTimeOffset(TimeSpan.FromHours(-1)),
309310
SomeNullableTimeSpan = TimeSpan.FromHours(1),
310311
SomeNullableEnum = DayOfWeek.Friday
311312
};

test/JsonApiDotNetCoreExampleTests/IntegrationTests/Filtering/FilterOperatorTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,7 +381,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
381381
httpResponse.Should().HaveStatusCode(HttpStatusCode.OK);
382382

383383
responseDocument.ManyData.Should().HaveCount(1);
384-
responseDocument.ManyData[0].Attributes["someDateTime"].Should().Be(resource.SomeDateTime);
384+
responseDocument.ManyData[0].Attributes["someDateTime"].Should().BeCloseTo(resource.SomeDateTime);
385385
}
386386

387387
[Theory]

test/JsonApiDotNetCoreExampleTests/IntegrationTests/Includes/IncludeTests.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
282282
responseDocument.Included.Should().HaveCount(1);
283283
responseDocument.Included[0].Type.Should().Be("revisions");
284284
responseDocument.Included[0].Id.Should().Be(article.Revisions.Single().StringId);
285-
responseDocument.Included[0].Attributes["publishTime"].Should().Be(article.Revisions.Single().PublishTime);
285+
responseDocument.Included[0].Attributes["publishTime"].Should().BeCloseTo(article.Revisions.Single().PublishTime);
286286
}
287287

288288
[Fact]
@@ -479,7 +479,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
479479

480480
responseDocument.Included[1].Type.Should().Be("revisions");
481481
responseDocument.Included[1].Id.Should().Be(blog.Articles[0].Revisions.Single().StringId);
482-
responseDocument.Included[1].Attributes["publishTime"].Should().Be(blog.Articles[0].Revisions.Single().PublishTime);
482+
responseDocument.Included[1].Attributes["publishTime"].Should().BeCloseTo(blog.Articles[0].Revisions.Single().PublishTime);
483483
}
484484

485485
[Fact]

test/JsonApiDotNetCoreExampleTests/IntegrationTests/NamingConventions/KebabCasingTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
5050
responseDocument.Included.Should().HaveCount(1);
5151
responseDocument.Included[0].Type.Should().Be("diving-boards");
5252
responseDocument.Included[0].Id.Should().Be(pools[1].DivingBoards[0].StringId);
53-
responseDocument.Included[0].Attributes["height-in-meters"].Should().BeApproximately(pools[1].DivingBoards[0].HeightInMeters);
53+
responseDocument.Included[0].Attributes["height-in-meters"].As<decimal>().Should().BeApproximately(pools[1].DivingBoards[0].HeightInMeters, 0.00000000001M);
5454
responseDocument.Included[0].Relationships.Should().BeNull();
5555
responseDocument.Included[0].Links.Self.Should().Be($"/public-api/diving-boards/{pools[1].DivingBoards[0].StringId}");
5656

test/JsonApiDotNetCoreExampleTests/IntegrationTests/ObjectAssertionsExtensions.cs

Lines changed: 8 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@ namespace JsonApiDotNetCoreExampleTests.IntegrationTests
77
public static class ObjectAssertionsExtensions
88
{
99
/// <summary>
10-
/// Used to assert on a nullable <see cref="DateTimeOffset"/> column, whose value is returned as <see cref="DateTime"/> in JSON:API response body.
10+
/// Used to assert on a (nullable) <see cref="DateTime"/> or <see cref="DateTimeOffset"/> property,
11+
/// whose value is returned as <see cref="string"/> in JSON:API response body
12+
/// because of <see cref="IntegrationTestConfiguration.DeserializationSettings"/>.
1113
/// </summary>
1214
public static void BeCloseTo(this ObjectAssertions source, DateTimeOffset? expected, string because = "",
1315
params object[] becauseArgs)
@@ -18,23 +20,14 @@ public static void BeCloseTo(this ObjectAssertions source, DateTimeOffset? expec
1820
}
1921
else
2022
{
21-
// We lose a little bit of precision (milliseconds) on roundtrip through PostgreSQL database.
23+
if (!DateTimeOffset.TryParse((string) source.Subject, out var value))
24+
{
25+
source.Subject.Should().Be(expected, because, becauseArgs);
26+
}
2227

23-
var value = new DateTimeOffset((DateTime) source.Subject);
28+
// We lose a little bit of precision (milliseconds) on roundtrip through PostgreSQL database.
2429
value.Should().BeCloseTo(expected.Value, because: because, becauseArgs: becauseArgs);
2530
}
2631
}
27-
28-
/// <summary>
29-
/// Used to assert on a <see cref="decimal"/> column, whose value is returned as <see cref="double"/> in json:api response body.
30-
/// </summary>
31-
public static void BeApproximately(this ObjectAssertions source, decimal? expected, decimal precision = 0.00000000001M, string because = "",
32-
params object[] becauseArgs)
33-
{
34-
// We lose a little bit of precision on roundtrip through PostgreSQL database.
35-
36-
var value = (decimal?) (double) source.Subject;
37-
value.Should().BeApproximately(expected, precision, because, becauseArgs);
38-
}
3932
}
4033
}

test/JsonApiDotNetCoreExampleTests/IntegrationTests/ResourceConstructorInjection/ResourceInjectionTests.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
1-
using System;
2-
using System.Linq;
31
using System.Net;
42
using System.Threading.Tasks;
53
using FluentAssertions;
4+
using FluentAssertions.Common;
65
using FluentAssertions.Extensions;
76
using JsonApiDotNetCore.Serialization.Objects;
87
using Microsoft.AspNetCore.Authentication;
@@ -56,7 +55,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
5655

5756
responseDocument.SingleData.Should().NotBeNull();
5857
responseDocument.SingleData.Id.Should().Be(certificate.StringId);
59-
responseDocument.SingleData.Attributes["issueDate"].Should().Be(certificate.IssueDate.DateTime);
58+
responseDocument.SingleData.Attributes["issueDate"].Should().BeCloseTo(certificate.IssueDate);
6059
responseDocument.SingleData.Attributes["hasExpired"].Should().Be(false);
6160
}
6261

@@ -129,7 +128,7 @@ public async Task Can_create_resource_with_ToOne_relationship_and_include()
129128

130129
var existingOffice = _fakers.PostOffice.Generate();
131130

132-
var newIssueDate = 18.March(1997);
131+
var newIssueDate = 18.March(1997).ToDateTimeOffset();
133132

134133
await _testContext.RunOnDatabaseAsync(async dbContext =>
135134
{
@@ -169,7 +168,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
169168
httpResponse.Should().HaveStatusCode(HttpStatusCode.Created);
170169

171170
responseDocument.SingleData.Should().NotBeNull();
172-
responseDocument.SingleData.Attributes["issueDate"].Should().Be(newIssueDate);
171+
responseDocument.SingleData.Attributes["issueDate"].Should().BeCloseTo(newIssueDate);
173172
responseDocument.SingleData.Attributes["hasExpired"].Should().Be(true);
174173
responseDocument.SingleData.Relationships["issuer"].SingleData.Id.Should().Be(existingOffice.StringId);
175174

test/JsonApiDotNetCoreExampleTests/IntegrationTests/SparseFieldSets/SparseFieldSetTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -641,7 +641,7 @@ await _testContext.RunOnDatabaseAsync(async dbContext =>
641641
responseDocument.Included[0].Id.Should().Be(blog.Owner.StringId);
642642
responseDocument.Included[0].Attributes["firstName"].Should().Be(blog.Owner.FirstName);
643643
responseDocument.Included[0].Attributes["lastName"].Should().Be(blog.Owner.LastName);
644-
responseDocument.Included[0].Attributes["dateOfBirth"].Should().Be(blog.Owner.DateOfBirth);
644+
responseDocument.Included[0].Attributes["dateOfBirth"].Should().BeCloseTo(blog.Owner.DateOfBirth);
645645
responseDocument.Included[0].Relationships["articles"].ManyData.Should().HaveCount(1);
646646
responseDocument.Included[0].Relationships["articles"].ManyData[0].Id.Should().Be(blog.Owner.Articles[0].StringId);
647647
responseDocument.Included[0].Relationships["articles"].Links.Self.Should().NotBeNull();

0 commit comments

Comments
 (0)