Skip to content

Commit 798fa68

Browse files
fix: Address TUnit migration issues from code review
- Fix 8 NRE occurrences in MarkdownChunkingServiceTests.cs: replace FirstOrDefault + .Header access with Assert.That(sections).Contains(predicate) - Remove redundant string.Join assertion (line 208) in MarkdownChunkingServiceTests.cs - Remove #pragma CA1707 disable/restore from MarkdownChunkingServiceTests.cs - Add CA1707 suppression to .editorconfig for test projects (replaces csproj NoWarn) - Remove <NoWarn>CA1707</NoWarn> from Web.Tests.csproj - Update TUnit 1.17.11 -> 1.17.20 in Directory.Packages.props - Add [NotInParallel('FunctionalTests')] to fix parallel SQLite transaction conflict: XUnit ran tests sequentially within a class; TUnit runs in parallel, causing multiple EF Core operations to call BeginTransaction on the same SQLite connection simultaneously - Add --coverage to CI dotnet test command (replaces removed coverlet.collector) - Add [Timeout(30_000)] with CancellationToken to CaptchaService_Verify_Success - Standardize StringComparison.OrdinalIgnoreCase in SitemapXmlHelpersTests URL predicates - Wrap foreach assertions with Assert.Multiple() in ListingSourceCode tests - Add IAsyncInitializer to WebApplicationFactory for eager server initialization
1 parent 2fcc896 commit 798fa68

File tree

11 files changed

+56
-55
lines changed

11 files changed

+56
-55
lines changed

.editorconfig

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,4 +156,7 @@ csharp_style_expression_bodied_lambdas = true:silent
156156
csharp_style_expression_bodied_local_functions = false:silent
157157

158158
# CA1848: Use the LoggerMessage delegates
159-
dotnet_diagnostic.CA1848.severity = suggestion
159+
dotnet_diagnostic.CA1848.severity = suggestion
160+
# Test files - allow underscore-separated test method names (CA1707)
161+
[{EssentialCSharp.Web.Tests,EssentialCSharp.Chat.Tests}/**]
162+
dotnet_diagnostic.CA1707.severity = none

.github/workflows/PR-Build-And-Test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ jobs:
3535
run: dotnet build --configuration Release --no-restore /p:AccessToNugetFeed=false
3636

3737
- name: Run .NET Tests
38-
run: dotnet test --no-build --configuration Release --report-trx --results-directory ${{ runner.temp }}
38+
run: dotnet test --no-build --configuration Release --report-trx --coverage --results-directory ${{ runner.temp }}
3939

4040
- name: Convert TRX to VS Playlist
4141
if: failure()

Directory.Packages.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
<PackageVersion Include="Azure.Identity" Version="1.17.1" />
2222
<PackageVersion Include="Azure.Monitor.OpenTelemetry.AspNetCore" Version="1.4.0" />
2323
<PackageVersion Include="Microsoft.ApplicationInsights.Profiler.AspNetCore" Version="3.0.1" />
24-
<PackageVersion Include="TUnit" Version="1.17.11" />
24+
<PackageVersion Include="TUnit" Version="1.17.20" />
2525
<PackageVersion Include="EssentialCSharp.Shared.Models" Version="$(ToolingPackagesVersion)" />
2626
<PackageVersion Include="HtmlAgilityPack" Version="1.12.4" />
2727
<PackageVersion Include="IntelliTect.Multitool" Version="1.5.3" />

EssentialCSharp.Chat.Tests/MarkdownChunkingServiceTests.cs

Lines changed: 13 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
using Moq;
33

44
namespace EssentialCSharp.Chat.Tests;
5-
// TODO: Move to editorconfig later, just moving quick
6-
#pragma warning disable CA1707 // Identifiers should not contain underscores
5+
76
public class MarkdownChunkingServiceTests
87
{
98
#region MarkdownContentToHeadersAndSection
@@ -44,18 +43,12 @@ publicstaticvoid Main() // Method declaration
4443
var sections = MarkdownChunkingService.MarkdownContentToHeadersAndSection(markdown);
4544

4645
await Assert.That(sections.Count).IsEqualTo(3);
47-
var beginnerSection = sections.FirstOrDefault(s => s.Header == "Beginner Topic: What Is a Method?");
48-
await Assert.That(beginnerSection.Header).IsNotNull();
49-
await Assert.That(string.Join("\n", beginnerSection.Content)).Contains("Syntactically, a **method** in C# is a named block of code");
50-
51-
var mainMethodSection = sections.FirstOrDefault(s => s.Header == "Main Method");
52-
await Assert.That(mainMethodSection.Header).IsNotNull();
53-
await Assert.That(string.Join("\n", mainMethodSection.Content)).Contains("The location where C# programs begin execution is the **Main method**, which begins with `static void Main()`");
54-
await Assert.That(string.Join("\n", mainMethodSection.Content)).Contains("publicclass Program");
55-
56-
var advancedTopicSection = sections.FirstOrDefault(s => s.Header == "Main Method: Advanced Topic: Declaration of the Main Method");
57-
await Assert.That(advancedTopicSection.Header).IsNotNull();
58-
await Assert.That(string.Join("\n", advancedTopicSection.Content)).Contains("C# requires that the Main method return either `void` or `int`");
46+
await Assert.That(sections).Contains(s => s.Header == "Beginner Topic: What Is a Method?" && string.Join("\n", s.Content).Contains("Syntactically, a **method** in C# is a named block of code"));
47+
48+
await Assert.That(sections).Contains(s => s.Header == "Main Method" && string.Join("\n", s.Content).Contains("The location where C# programs begin execution is the **Main method**, which begins with `static void Main()`"));
49+
await Assert.That(sections).Contains(s => s.Header == "Main Method" && string.Join("\n", s.Content).Contains("publicclass Program"));
50+
51+
await Assert.That(sections).Contains(s => s.Header == "Main Method: Advanced Topic: Declaration of the Main Method" && string.Join("\n", s.Content).Contains("C# requires that the Main method return either `void` or `int`"));
5952
}
6053

6154
[Test]
@@ -96,9 +89,7 @@ publicstaticvoid Main()
9689

9790
await Assert.That(sections.Count).IsEqualTo(2);
9891
// The code listing should be appended to the Working with Variables section, not as its own section
99-
var workingWithVariablesSection = sections.FirstOrDefault(s => s.Header == "Working with Variables");
100-
await Assert.That(workingWithVariablesSection.Header).IsNotNull().And.IsNotEmpty();
101-
await Assert.That(string.Join("\n", workingWithVariablesSection.Content)).Contains("publicclass MiracleMax");
92+
await Assert.That(sections).Contains(s => s.Header == "Working with Variables" && string.Join("\n", s.Content).Contains("publicclass MiracleMax"));
10293
await Assert.That(sections).DoesNotContain(s => s.Header == "Listing 1.12: Declaring and Assigning a Variable");
10394
}
10495

@@ -153,25 +144,15 @@ publicstaticvoid Main()
153144
var sections = MarkdownChunkingService.MarkdownContentToHeadersAndSection(markdown);
154145
await Assert.That(sections.Count).IsEqualTo(5);
155146

156-
var beginnerDataTypeSection = sections.FirstOrDefault(s => s.Header == "Beginner Topic: What Is a Data Type?");
157-
await Assert.That(beginnerDataTypeSection.Header).IsNotNull();
158-
await Assert.That(string.Join("\n", beginnerDataTypeSection.Content)).Contains("The type of data that a variable declaration specifies is called a **data type**");
147+
await Assert.That(sections).Contains(s => s.Header == "Beginner Topic: What Is a Data Type?" && string.Join("\n", s.Content).Contains("The type of data that a variable declaration specifies is called a **data type**"));
159148

160-
var declaringSection = sections.FirstOrDefault(s => s.Header == "Declaring a Variable");
161-
await Assert.That(declaringSection.Header).IsNotNull();
162-
await Assert.That(string.Join("\n", declaringSection.Content)).Contains("In Listing 1.12, `string max` is a variable declaration");
149+
await Assert.That(sections).Contains(s => s.Header == "Declaring a Variable" && string.Join("\n", s.Content).Contains("In Listing 1.12, `string max` is a variable declaration"));
163150

164-
var declaringAnotherSection = sections.FirstOrDefault(s => s.Header == "Declaring a Variable: Declaring another thing");
165-
await Assert.That(declaringAnotherSection.Header).IsNotNull();
166-
await Assert.That(string.Join("\n", declaringAnotherSection.Content)).Contains("Because a multivariable declaration statement allows developers to provide the data type only once");
151+
await Assert.That(sections).Contains(s => s.Header == "Declaring a Variable: Declaring another thing" && string.Join("\n", s.Content).Contains("Because a multivariable declaration statement allows developers to provide the data type only once"));
167152

168-
var assigningSection = sections.FirstOrDefault(s => s.Header == "Assigning a Variable");
169-
await Assert.That(assigningSection.Header).IsNotNull();
170-
await Assert.That(string.Join("\n", assigningSection.Content)).Contains("After declaring a local variable, you must assign it a value before reading from it.");
153+
await Assert.That(sections).Contains(s => s.Header == "Assigning a Variable" && string.Join("\n", s.Content).Contains("After declaring a local variable, you must assign it a value before reading from it."));
171154

172-
var continuedLearningSection = sections.FirstOrDefault(s => s.Header == "Assigning a Variable: Continued Learning");
173-
await Assert.That(continuedLearningSection.Header).IsNotNull();
174-
await Assert.That(string.Join("\n", continuedLearningSection.Content)).Contains("From this listing, observe that it is possible to assign a variable as part of the variable declaration");
155+
await Assert.That(sections).Contains(s => s.Header == "Assigning a Variable: Continued Learning" && string.Join("\n", s.Content).Contains("From this listing, observe that it is possible to assign a variable as part of the variable declaration"));
175156
}
176157
#endregion MarkdownContentToHeadersAndSection
177158

@@ -205,10 +186,7 @@ public async Task ProcessSingleMarkdownFile_ProducesExpectedChunksAndHeaders()
205186
await Assert.That(result.FilePath).IsEqualTo(filePath);
206187
await Assert.That(string.Join("\n", result.Chunks)).Contains("This is the first section.");
207188
await Assert.That(string.Join("\n", result.Chunks)).Contains("Console.WriteLine(\"Hello World\");");
208-
await Assert.That(string.Join("\n", result.Chunks)).Contains("This is the second section.");
209189
await Assert.That(result.Chunks).Contains(c => c.Contains("This is the second section."));
210190
}
211191
#endregion ProcessSingleMarkdownFile
212192
}
213-
214-
#pragma warning restore CA1707 // Identifiers should not contain underscores

EssentialCSharp.Web.Tests/EssentialCSharp.Web.Tests.csproj

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

66
<IsPackable>false</IsPackable>
77
<IsPublishable>false</IsPublishable>
8-
<!--
9-
CA1707, Identifiers should not contain underscores - we allow these in test names
10-
-->
11-
<NoWarn>$(NoWarn);CA1707</NoWarn>
128
</PropertyGroup>
139

1410
<ItemGroup>

EssentialCSharp.Web.Tests/FunctionalTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
namespace EssentialCSharp.Web.Tests;
44

5+
[NotInParallel("FunctionalTests")]
56
[ClassDataSource<WebApplicationFactory>(Shared = SharedType.PerClass)]
67
public class FunctionalTests(WebApplicationFactory factory)
78
{

EssentialCSharp.Web.Tests/Integration/CaptchaTests.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ namespace EssentialCSharp.Web.Extensions.Tests.Integration;
99
public class CaptchaTests(CaptchaServiceProvider serviceProvider)
1010
{
1111
[Test]
12-
public async Task CaptchaService_Verify_Success()
12+
[Timeout(30_000)]
13+
public async Task CaptchaService_Verify_Success(CancellationToken cancellationToken)
1314
{
1415
ICaptchaService captchaService = serviceProvider.ServiceProvider.GetRequiredService<ICaptchaService>();
1516

EssentialCSharp.Web.Tests/ListingSourceCodeControllerTests.cs

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,10 @@ public async Task GetListingsByChapter_WithValidChapter_ReturnsMultipleListings(
7676
// Verify all results are from chapter 1
7777
foreach (var r in results)
7878
{
79-
await Assert.That(r.ChapterNumber).IsEqualTo(1);
79+
using (Assert.Multiple())
80+
{
81+
await Assert.That(r.ChapterNumber).IsEqualTo(1);
82+
}
8083
}
8184

8285
// Verify results are ordered by listing number
@@ -85,8 +88,11 @@ public async Task GetListingsByChapter_WithValidChapter_ReturnsMultipleListings(
8588
// Verify each listing has required properties
8689
foreach (var r in results)
8790
{
88-
await Assert.That(r.FileExtension).IsNotEmpty();
89-
await Assert.That(r.Content).IsNotEmpty();
91+
using (Assert.Multiple())
92+
{
93+
await Assert.That(r.FileExtension).IsNotEmpty();
94+
await Assert.That(r.Content).IsNotEmpty();
95+
}
9096
}
9197
}
9298

EssentialCSharp.Web.Tests/ListingSourceCodeServiceTests.cs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,12 @@ public async Task GetListingsByChapterAsync_WithValidChapter_ReturnsAllListings(
8282
await Assert.That(results).IsNotEmpty();
8383
foreach (var r in results)
8484
{
85-
await Assert.That(r.ChapterNumber).IsEqualTo(1);
86-
await Assert.That(r.Content).IsNotEmpty();
87-
await Assert.That(r.FileExtension).IsNotEmpty();
85+
using (Assert.Multiple())
86+
{
87+
await Assert.That(r.ChapterNumber).IsEqualTo(1);
88+
await Assert.That(r.Content).IsNotEmpty();
89+
await Assert.That(r.FileExtension).IsNotEmpty();
90+
}
8891
}
8992

9093
// Verify results are ordered
@@ -106,8 +109,11 @@ public async Task GetListingsByChapterAsync_DirectoryContainsNonListingFiles_Exc
106109
// Ensure all results match the {CC}.{LL}.{ext} pattern
107110
foreach (var r in results)
108111
{
109-
await Assert.That(r.ChapterNumber).IsEqualTo(10);
110-
await Assert.That(r.ListingNumber).IsBetween(1, 99);
112+
using (Assert.Multiple())
113+
{
114+
await Assert.That(r.ChapterNumber).IsEqualTo(10);
115+
await Assert.That(r.ListingNumber).IsBetween(1, 99);
116+
}
111117
}
112118
}
113119

EssentialCSharp.Web.Tests/SitemapXmlHelpersTests.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,9 @@ public async Task GenerateSitemapXml_IncludesSiteMappingsMarkedForXml()
147147

148148
var allUrls = nodes.Select(n => n.Url).ToList();
149149

150-
await Assert.That(allUrls).Contains(url => url.Contains("test-page-1"));
151-
await Assert.That(allUrls).DoesNotContain(url => url.Contains("test-page-2")); // Not marked for XML
152-
await Assert.That(allUrls).Contains(url => url.Contains("test-page-3"));
150+
await Assert.That(allUrls).Contains(url => url.Contains("test-page-1", StringComparison.OrdinalIgnoreCase));
151+
await Assert.That(allUrls).DoesNotContain(url => url.Contains("test-page-2", StringComparison.OrdinalIgnoreCase)); // Not marked for XML
152+
await Assert.That(allUrls).Contains(url => url.Contains("test-page-3", StringComparison.OrdinalIgnoreCase));
153153
}
154154

155155
[Test]

0 commit comments

Comments
 (0)