diff --git a/.reviewmark.yaml b/.reviewmark.yaml index f4a0cba..893706c 100644 --- a/.reviewmark.yaml +++ b/.reviewmark.yaml @@ -103,8 +103,10 @@ reviews: - id: TestResults-IO-SerializerHelpers title: Review that TestResults IO SerializerHelpers Implementation is Correct paths: + - "docs/reqstream/test-results-library/io/serializer-helpers.yaml" - "docs/design/test-results-library/io/serializer-helpers.md" - "src/DemaConsulting.TestResults/IO/SerializerHelpers.cs" + - "test/DemaConsulting.TestResults.Tests/IO/SerializerHelpersTests.cs" - id: TestResults-IO-TrxSerializer title: Review that TestResults IO TrxSerializer Implementation is Correct diff --git a/README.md b/README.md index 0f5fb5b..fbb27bf 100644 --- a/README.md +++ b/README.md @@ -163,7 +163,6 @@ The library supports the following test outcomes: - `Passed` - Test passed successfully - `PassedButRunAborted` - Test passed but the run was aborted - `Warning` - Test passed with warnings -- `Completed` - Test completed successfully **Failure Outcomes:** @@ -180,6 +179,7 @@ The library supports the following test outcomes: **Other Outcomes:** +- `Completed` - Test completed successfully - `Inconclusive` - Test result was inconclusive - `Disconnected` - Test was disconnected - `InProgress` - Test is currently in progress @@ -230,24 +230,15 @@ dotnet test For convenience, the repository includes helper scripts to streamline development: -**Windows:** - ```bash # Build and test the project -build.bat +pwsh ./build.ps1 # Run code formatting, spelling, and markdown checks -lint.bat -``` - -**Linux/macOS:** +pwsh ./lint.ps1 -```bash -# Build and test the project -./build.sh - -# Run code formatting, spelling, and markdown checks -./lint.sh +# Auto-fix formatting issues +pwsh ./fix.ps1 ``` **Visual Studio Code:** @@ -306,6 +297,6 @@ Developed and maintained by [DEMA Consulting](https://github.com/demaconsulting) [link-nuget]: https://www.nuget.org/packages/DemaConsulting.TestResults -[architecture]: https://github.com/demaconsulting/TestResults/blob/main/ARCHITECTURE.md +[architecture]: https://github.com/demaconsulting/TestResults/blob/main/docs/design/introduction.md [contributing]: https://github.com/demaconsulting/TestResults/blob/main/CONTRIBUTING.md [code-of-conduct]: https://github.com/demaconsulting/TestResults/blob/main/CODE_OF_CONDUCT.md diff --git a/docs/design/introduction.md b/docs/design/introduction.md index 6065fe8..0fa5a5b 100644 --- a/docs/design/introduction.md +++ b/docs/design/introduction.md @@ -89,5 +89,43 @@ src/DemaConsulting.TestResults/ └── TestResults.cs — Collection of test results (TestResults unit) ``` -[user-guide]: https://github.com/demaconsulting/TestResults -[requirements-doc]: https://github.com/demaconsulting/TestResults +## Companion Artifact Structure + +Each design unit has corresponding artifacts across requirements, source, tests, and +review-set entries, forming end-to-end traceability: + +```text +requirements.yaml — System-level requirements (TestResults-*) +docs/reqstream/test-results-library/ — Unit-level requirements +├── io/ +│ ├── io.yaml — IO Subsystem requirements +│ ├── serializer.yaml — Serializer unit requirements +│ ├── serializer-helpers.yaml — SerializerHelpers unit requirements +│ ├── trx-serializer.yaml — TrxSerializer unit requirements +│ └── junit-serializer.yaml — JUnitSerializer unit requirements +├── test-outcome.yaml — TestOutcome unit requirements +├── test-result.yaml — TestResult unit requirements +└── test-results.yaml — TestResults unit requirements +docs/design/ — Design documentation (this document and sub-documents) +├── test-results-library/ +│ ├── io/ — IO Subsystem design +│ ├── test-outcome.md — TestOutcome unit design +│ ├── test-result.md — TestResult unit design +│ └── test-results.md — TestResults unit design +src/DemaConsulting.TestResults/ — Source implementation +└── IO/ + ├── Serializer.cs + ├── SerializerHelpers.cs + ├── TrxSerializer.cs + └── JUnitSerializer.cs +test/DemaConsulting.TestResults.Tests/ — Unit tests +└── IO/ + ├── IOTests.cs + ├── SerializerTests.cs + ├── SerializerHelpersTests.cs + ├── TrxSerializerTests.cs + └── JUnitSerializerTests.cs +``` + +[user-guide]: https://github.com/demaconsulting/TestResults/blob/main/docs/user_guide/introduction.md +[requirements-doc]: https://github.com/demaconsulting/TestResults/blob/main/requirements.yaml diff --git a/docs/design/test-results-library/io/serializer-helpers.md b/docs/design/test-results-library/io/serializer-helpers.md index 4e9b774..c83d345 100644 --- a/docs/design/test-results-library/io/serializer-helpers.md +++ b/docs/design/test-results-library/io/serializer-helpers.md @@ -15,5 +15,5 @@ to write `encoding="utf-16"` in the XML declaration even when the resulting stri later converted to UTF-8 bytes. `Utf8StringWriter` overrides the `Encoding` property to return `Encoding.UTF8`, so the -XML declaration correctly declares `encoding="UTF-8"`. It is used by both +XML declaration correctly declares `encoding="utf-8"`. It is used by both `TrxSerializer.Serialize()` and `JUnitSerializer.Serialize()`. diff --git a/docs/design/test-results-library/io/serializer.md b/docs/design/test-results-library/io/serializer.md index ece8210..ecd275b 100644 --- a/docs/design/test-results-library/io/serializer.md +++ b/docs/design/test-results-library/io/serializer.md @@ -55,6 +55,6 @@ pass the raw content and receive a `TestResults` object. ## SerializerHelpers Dependency -The `Serializer.Deserialize()` method delegates writing to format-specific serializers -that depend on the [SerializerHelpers](serializer-helpers.md) unit for UTF-8 output -encoding. See [serializer-helpers.md](serializer-helpers.md) for details. +The `TrxSerializer.Serialize()` and `JUnitSerializer.Serialize()` methods both depend +on the [SerializerHelpers](serializer-helpers.md) unit for UTF-8 output encoding. +See [serializer-helpers.md](serializer-helpers.md) for details. diff --git a/docs/reqstream/test-results-library/io/io.yaml b/docs/reqstream/test-results-library/io/io.yaml index 2893831..3c15d0c 100644 --- a/docs/reqstream/test-results-library/io/io.yaml +++ b/docs/reqstream/test-results-library/io/io.yaml @@ -3,7 +3,6 @@ # This file covers the IO subsystem of the TestResults library. # Unit-level requirements are in the individual unit files: # - serializer.yaml -# - serializer-helpers.yaml # - trx-serializer.yaml # - junit-serializer.yaml @@ -49,6 +48,7 @@ sections: children: - TestResults-Trx-Serialize - TestResults-JUnit-Serialize + - TestResults-SerializerHelpers-Utf8Encoding tests: - IO_Serialize_TestResults_ProducesTrxContent - IO_Serialize_TestResults_ProducesJUnitContent diff --git a/docs/reqstream/test-results-library/io/serializer-helpers.yaml b/docs/reqstream/test-results-library/io/serializer-helpers.yaml new file mode 100644 index 0000000..7d585b3 --- /dev/null +++ b/docs/reqstream/test-results-library/io/serializer-helpers.yaml @@ -0,0 +1,31 @@ +--- +# Software Unit Requirements for the SerializerHelpers Unit +# +# DERIVATION NOTE: These requirements are a top-down decomposition of +# TestResults-IO-Serialize (io.yaml). The IO subsystem's obligation to produce +# correctly-encoded XML serialized output decomposes into three sibling unit +# responsibilities: TrxSerializer, JUnitSerializer, and SerializerHelpers. +# SerializerHelpers satisfies the shared encoding constraint that both XML +# serializer units depend on. +# +# These requirements were NOT derived from or driven by the existing +# implementation. The need for a correct UTF-8 encoding declaration is an +# interoperability constraint placed on the IO subsystem by downstream XML +# consumers; SerializerHelpers is the unit that satisfies that constraint +# on behalf of both serializer units. + +sections: + - title: SerializerHelpers Unit Requirements + requirements: + - id: TestResults-SerializerHelpers-Utf8Encoding + title: The SerializerHelpers unit shall provide a string writer that reports UTF-8 as its character encoding. + justification: | + XML serializers read the encoding reported by their underlying string writer to + determine which encoding declaration to emit in the XML prolog. The IO subsystem + must produce XML output that declares encoding="utf-8" so that downstream tools + correctly interpret the byte stream. The default StringWriter reports UTF-16, which + would produce an incorrect declaration. This unit satisfies the encoding constraint + shared by both TrxSerializer and JUnitSerializer by providing a writer that correctly + reports UTF-8, decomposing the TestResults-IO-Serialize obligation. + tests: + - Utf8StringWriter_Encoding_ReturnsUtf8 diff --git a/requirements.yaml b/requirements.yaml index 64a477e..6e97ba8 100644 --- a/requirements.yaml +++ b/requirements.yaml @@ -11,6 +11,7 @@ includes: - docs/reqstream/test-results-library/test-result.yaml - docs/reqstream/test-results-library/io/io.yaml - docs/reqstream/test-results-library/io/serializer.yaml + - docs/reqstream/test-results-library/io/serializer-helpers.yaml - docs/reqstream/test-results-library/io/trx-serializer.yaml - docs/reqstream/test-results-library/io/junit-serializer.yaml - docs/reqstream/test-results-library/platform-requirements.yaml diff --git a/src/DemaConsulting.TestResults/IO/SerializerHelpers.cs b/src/DemaConsulting.TestResults/IO/SerializerHelpers.cs index cba7b2e..5f4626f 100644 --- a/src/DemaConsulting.TestResults/IO/SerializerHelpers.cs +++ b/src/DemaConsulting.TestResults/IO/SerializerHelpers.cs @@ -23,12 +23,23 @@ namespace DemaConsulting.TestResults.IO; /// -/// String writer that uses UTF-8 encoding +/// String writer that reports UTF-8 as its encoding. /// +/// +/// reads the +/// property of the underlying writer to determine which encoding declaration to emit in the +/// XML prolog. The default reports UTF-16 (the .NET in-memory +/// string encoding), which would cause serializers to write encoding="utf-16" even +/// when the resulting string is later consumed or stored as UTF-8. This class overrides +/// to return so that the +/// XML declaration correctly declares encoding="utf-8". +/// internal sealed class Utf8StringWriter : StringWriter { /// - /// Gets the UTF-8 encoding + /// Gets the UTF-8 encoding, overriding the default UTF-16 reported by + /// so that XML serializers emit the correct + /// encoding="utf-8" declaration in the XML prolog. /// public override Encoding Encoding => Encoding.UTF8; } diff --git a/test/DemaConsulting.TestResults.Tests/IO/SerializerHelpersTests.cs b/test/DemaConsulting.TestResults.Tests/IO/SerializerHelpersTests.cs new file mode 100644 index 0000000..456cd57 --- /dev/null +++ b/test/DemaConsulting.TestResults.Tests/IO/SerializerHelpersTests.cs @@ -0,0 +1,48 @@ +// Copyright(c) 2025 DEMA Consulting +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all +// copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +using System.Text; +using DemaConsulting.TestResults.IO; +using Microsoft.VisualStudio.TestTools.UnitTesting; + +namespace DemaConsulting.TestResults.Tests.IO; + +/// +/// Tests for SerializerHelpers unit +/// +[TestClass] +public sealed class SerializerHelpersTests +{ + /// + /// Test that Utf8StringWriter reports UTF-8 as its encoding + /// + [TestMethod] + public void Utf8StringWriter_Encoding_ReturnsUtf8() + { + // Arrange: create a Utf8StringWriter + using var writer = new Utf8StringWriter(); + + // Act: read the reported encoding + var encoding = writer.Encoding; + + // Assert: encoding is UTF-8 + Assert.AreEqual(Encoding.UTF8, encoding); + } +} diff --git a/test/DemaConsulting.TestResults.Tests/IO/SerializerTests.cs b/test/DemaConsulting.TestResults.Tests/IO/SerializerTests.cs index 929f5d4..2453b16 100644 --- a/test/DemaConsulting.TestResults.Tests/IO/SerializerTests.cs +++ b/test/DemaConsulting.TestResults.Tests/IO/SerializerTests.cs @@ -35,7 +35,7 @@ public sealed class SerializerTests [TestMethod] public void Serializer_Identify_TrxContent_ReturnsTrx() { - // Create a sample TRX content + // Arrange: create a sample TRX content var trxContent = """ @@ -62,10 +62,10 @@ public void Serializer_Identify_TrxContent_ReturnsTrx() """; - // Identify format + // Act: identify format var format = Serializer.Identify(trxContent); - // Verify it's identified as TRX + // Assert: verify it's identified as TRX Assert.AreEqual(TestResultFormat.Trx, format); } @@ -75,7 +75,7 @@ public void Serializer_Identify_TrxContent_ReturnsTrx() [TestMethod] public void Serializer_Identify_JUnitTestsuitesContent_ReturnsJUnit() { - // Create a sample JUnit content with testsuites root + // Arrange: create a sample JUnit content with testsuites root var junitContent = """ @@ -85,10 +85,10 @@ public void Serializer_Identify_JUnitTestsuitesContent_ReturnsJUnit() """; - // Identify format + // Act: identify format var format = Serializer.Identify(junitContent); - // Verify it's identified as JUnit + // Assert: verify it's identified as JUnit Assert.AreEqual(TestResultFormat.JUnit, format); } @@ -98,7 +98,7 @@ public void Serializer_Identify_JUnitTestsuitesContent_ReturnsJUnit() [TestMethod] public void Serializer_Identify_JUnitTestsuiteContent_ReturnsJUnit() { - // Create a sample JUnit content with testsuite root + // Arrange: create a sample JUnit content with testsuite root var junitContent = """ @@ -106,10 +106,10 @@ public void Serializer_Identify_JUnitTestsuiteContent_ReturnsJUnit() """; - // Identify format + // Act: identify format var format = Serializer.Identify(junitContent); - // Verify it's identified as JUnit + // Assert: verify it's identified as JUnit Assert.AreEqual(TestResultFormat.JUnit, format); } @@ -119,10 +119,10 @@ public void Serializer_Identify_JUnitTestsuiteContent_ReturnsJUnit() [TestMethod] public void Serializer_Identify_EmptyContent_ReturnsUnknown() { - // Identify format of empty string + // Act: identify format of empty string var format = Serializer.Identify(string.Empty); - // Verify it's identified as Unknown + // Assert: verify it's identified as Unknown Assert.AreEqual(TestResultFormat.Unknown, format); } @@ -132,10 +132,10 @@ public void Serializer_Identify_EmptyContent_ReturnsUnknown() [TestMethod] public void Serializer_Identify_NullContent_ReturnsUnknown() { - // Identify format of null string + // Act: identify format of null string var format = Serializer.Identify(null!); - // Verify it's identified as Unknown + // Assert: verify it's identified as Unknown Assert.AreEqual(TestResultFormat.Unknown, format); } @@ -145,10 +145,10 @@ public void Serializer_Identify_NullContent_ReturnsUnknown() [TestMethod] public void Serializer_Identify_WhitespaceContent_ReturnsUnknown() { - // Identify format of whitespace string + // Act: identify format of whitespace string var format = Serializer.Identify(" \n\t "); - // Verify it's identified as Unknown + // Assert: verify it's identified as Unknown Assert.AreEqual(TestResultFormat.Unknown, format); } @@ -158,13 +158,13 @@ public void Serializer_Identify_WhitespaceContent_ReturnsUnknown() [TestMethod] public void Serializer_Identify_InvalidXml_ReturnsUnknown() { - // Create invalid XML content + // Arrange: create invalid XML content var invalidXml = ""; - // Identify format + // Act: identify format var format = Serializer.Identify(invalidXml); - // Verify it's identified as Unknown + // Assert: verify it's identified as Unknown Assert.AreEqual(TestResultFormat.Unknown, format); } @@ -174,7 +174,7 @@ public void Serializer_Identify_InvalidXml_ReturnsUnknown() [TestMethod] public void Serializer_Identify_UnrecognizedXmlFormat_ReturnsUnknown() { - // Create XML with unrecognized root element + // Arrange: create XML with unrecognized root element var unrecognizedXml = """ @@ -182,10 +182,10 @@ public void Serializer_Identify_UnrecognizedXmlFormat_ReturnsUnknown() """; - // Identify format + // Act: identify format var format = Serializer.Identify(unrecognizedXml); - // Verify it's identified as Unknown + // Assert: verify it's identified as Unknown Assert.AreEqual(TestResultFormat.Unknown, format); } @@ -195,7 +195,7 @@ public void Serializer_Identify_UnrecognizedXmlFormat_ReturnsUnknown() [TestMethod] public void Serializer_Deserialize_TrxContent_ReturnsTestResults() { - // Create a sample TRX content + // Arrange: create a sample TRX content var trxContent = """ @@ -222,10 +222,10 @@ public void Serializer_Deserialize_TrxContent_ReturnsTestResults() """; - // Deserialize + // Act: deserialize var results = Serializer.Deserialize(trxContent); - // Verify results + // Assert: verify results Assert.IsNotNull(results); Assert.AreEqual("Test Run", results.Name); Assert.AreEqual("User", results.UserName); @@ -240,7 +240,7 @@ public void Serializer_Deserialize_TrxContent_ReturnsTestResults() [TestMethod] public void Serializer_Deserialize_JUnitContent_ReturnsTestResults() { - // Create a sample JUnit content + // Arrange: create a sample JUnit content var junitContent = """ @@ -253,10 +253,10 @@ public void Serializer_Deserialize_JUnitContent_ReturnsTestResults() """; - // Deserialize + // Act: deserialize var results = Serializer.Deserialize(junitContent); - // Verify results + // Assert: verify results Assert.IsNotNull(results); Assert.AreEqual("Test Suite", results.Name); Assert.HasCount(2, results.Results); @@ -273,18 +273,20 @@ public void Serializer_Deserialize_JUnitContent_ReturnsTestResults() [TestMethod] public void Serializer_Deserialize_RealTrxExample_ReturnsTestResults() { - // Load example TRX file + // Arrange: load example TRX file var trxContent = TestHelpers.GetEmbeddedResource( "DemaConsulting.TestResults.Tests.IO.Examples.example1.trx"); - // Identify and verify format + // Act: identify format var format = Serializer.Identify(trxContent); + + // Assert: verify format Assert.AreEqual(TestResultFormat.Trx, format); - // Deserialize + // Act: deserialize var results = Serializer.Deserialize(trxContent); - // Verify results + // Assert: verify results Assert.IsNotNull(results); Assert.AreEqual("Sample TRX Import", results.Name); Assert.AreEqual("Brian Mancini", results.UserName); @@ -297,7 +299,7 @@ public void Serializer_Deserialize_RealTrxExample_ReturnsTestResults() [TestMethod] public void Serializer_Deserialize_TrxWithMultipleOutcomes_ParsesCorrectly() { - // Create TRX content with different outcomes + // Arrange: create TRX content with different outcomes var trxContent = """ @@ -336,10 +338,10 @@ public void Serializer_Deserialize_TrxWithMultipleOutcomes_ParsesCorrectly() """; - // Deserialize + // Act: deserialize var results = Serializer.Deserialize(trxContent); - // Verify results + // Assert: verify results Assert.IsNotNull(results); Assert.HasCount(2, results.Results); @@ -359,7 +361,7 @@ public void Serializer_Deserialize_TrxWithMultipleOutcomes_ParsesCorrectly() [TestMethod] public void Serializer_Deserialize_JUnitWithSystemOutput_ParsesCorrectly() { - // Create JUnit content with system output + // Arrange: create JUnit content with system output var junitContent = """ @@ -372,10 +374,10 @@ public void Serializer_Deserialize_JUnitWithSystemOutput_ParsesCorrectly() """; - // Deserialize + // Act: deserialize var results = Serializer.Deserialize(junitContent); - // Verify results + // Assert: verify results Assert.IsNotNull(results); Assert.HasCount(1, results.Results); Assert.AreEqual("Test1", results.Results[0].Name); diff --git a/test/DemaConsulting.TestResults.Tests/IO/TrxSerializerTests.cs b/test/DemaConsulting.TestResults.Tests/IO/TrxSerializerTests.cs index afdda6f..e3d8f80 100644 --- a/test/DemaConsulting.TestResults.Tests/IO/TrxSerializerTests.cs +++ b/test/DemaConsulting.TestResults.Tests/IO/TrxSerializerTests.cs @@ -45,7 +45,7 @@ public sealed class TrxSerializerTests [TestMethod] public void TrxSerializer_Serialize_BasicTestResults_ProducesValidTrxXml() { - // Construct a basic test results object + // Arrange: construct a basic test results object var suites = new TestResults { Name = "Basic", @@ -65,22 +65,24 @@ public void TrxSerializer_Serialize_BasicTestResults_ProducesValidTrxXml() ] }; - // Serialize the test suites object + // Act: serialize the test suites object var result = TrxSerializer.Serialize(suites); + + // Assert: verify the serialized result is present Assert.IsNotNull(result); - // Parse the document + // Assert: parse the document var doc = XDocument.Parse(result); var nsMgr = new XmlNamespaceManager(new NameTable()); nsMgr.AddNamespace("trx", TrxNamespace); - // Verify the UnitTestResult element is present + // Assert: verify the UnitTestResult element is present Assert.IsNotNull(doc.XPathSelectElement("/trx:TestRun/trx:Results/trx:UnitTestResult[@testName='Test']", nsMgr)); - // Verify the UnitTest element is present + // Assert: verify the UnitTest element is present Assert.IsNotNull(doc.XPathSelectElement("/trx:TestRun/trx:TestDefinitions/trx:UnitTest[@name='Test']", nsMgr)); - // Verify the Counters element is present + // Assert: verify the Counters element is present Assert.IsNotNull(doc.XPathSelectElement("/trx:TestRun/trx:ResultSummary/trx:Counters[@total='1']", nsMgr)); Assert.IsNotNull(doc.XPathSelectElement("/trx:TestRun/trx:ResultSummary/trx:Counters[@executed='1']", nsMgr)); Assert.IsNotNull(doc.XPathSelectElement("/trx:TestRun/trx:ResultSummary/trx:Counters[@passed='1']", nsMgr)); @@ -93,7 +95,7 @@ public void TrxSerializer_Serialize_BasicTestResults_ProducesValidTrxXml() [TestMethod] public void TrxSerializer_Serialize_MultipleTestResults_ProducesValidTrxXml() { - // Construct a complex test results object + // Arrange: construct a complex test results object var suites = new TestResults { Name = "Basic", @@ -124,24 +126,26 @@ public void TrxSerializer_Serialize_MultipleTestResults_ProducesValidTrxXml() ] }; - // Serialize the test suites object + // Act: serialize the test suites object var result = TrxSerializer.Serialize(suites); + + // Assert: verify the serialized result is present Assert.IsNotNull(result); - // Parse the document + // Assert: parse the document var doc = XDocument.Parse(result); var nsMgr = new XmlNamespaceManager(new NameTable()); nsMgr.AddNamespace("trx", TrxNamespace); - // Verify the UnitTestResult elements are present + // Assert: verify the UnitTestResult elements are present Assert.IsNotNull(doc.XPathSelectElement("/trx:TestRun/trx:Results/trx:UnitTestResult[@testName='Test1']", nsMgr)); Assert.IsNotNull(doc.XPathSelectElement("/trx:TestRun/trx:Results/trx:UnitTestResult[@testName='Test2']", nsMgr)); - // Verify the UnitTest elements are present + // Assert: verify the UnitTest elements are present Assert.IsNotNull(doc.XPathSelectElement("/trx:TestRun/trx:TestDefinitions/trx:UnitTest[@name='Test1']", nsMgr)); Assert.IsNotNull(doc.XPathSelectElement("/trx:TestRun/trx:TestDefinitions/trx:UnitTest[@name='Test2']", nsMgr)); - // Verify the Counters element is present + // Assert: verify the Counters element is present Assert.IsNotNull(doc.XPathSelectElement("/trx:TestRun/trx:ResultSummary/trx:Counters[@total='2']", nsMgr)); Assert.IsNotNull(doc.XPathSelectElement("/trx:TestRun/trx:ResultSummary/trx:Counters[@executed='2']", nsMgr)); Assert.IsNotNull(doc.XPathSelectElement("/trx:TestRun/trx:ResultSummary/trx:Counters[@passed='1']", nsMgr)); @@ -154,7 +158,7 @@ public void TrxSerializer_Serialize_MultipleTestResults_ProducesValidTrxXml() [TestMethod] public void TrxSerializer_Deserialize_BasicTrxXml_ReturnsTestResults() { - // Deserialize the test results object + // Act: deserialize the test results object var results = TrxSerializer.Deserialize( """ @@ -211,7 +215,7 @@ public void TrxSerializer_Deserialize_BasicTrxXml_ReturnsTestResults() [TestMethod] public void TrxSerializer_Deserialize_ComplexTrxXml_ReturnsTestResults() { - // Deserialize the test results object + // Act: deserialize the test results object var results = TrxSerializer.Deserialize( """ @@ -295,7 +299,7 @@ public void TrxSerializer_Deserialize_ComplexTrxXml_ReturnsTestResults() [TestMethod] public void TrxSerializer_Serialize_StackTraceWithoutMessage_IncludesStackTraceElement() { - // Construct a test results object with stack trace but no message + // Arrange: construct a test results object with stack trace but no message var suites = new TestResults { Name = "StackTraceOnly", @@ -315,16 +319,18 @@ public void TrxSerializer_Serialize_StackTraceWithoutMessage_IncludesStackTraceE ] }; - // Serialize the test suites object + // Act: serialize the test suites object var result = TrxSerializer.Serialize(suites); + + // Assert: verify the serialized result is present Assert.IsNotNull(result); - // Parse the document + // Assert: parse the document var doc = XDocument.Parse(result); var nsMgr = new XmlNamespaceManager(new NameTable()); nsMgr.AddNamespace("trx", TrxNamespace); - // Verify the StackTrace element is present + // Assert: verify the StackTrace element is present var stackTraceElement = doc.XPathSelectElement( "/trx:TestRun/trx:Results/trx:UnitTestResult[@testName='TestWithStackTrace']/trx:Output/trx:ErrorInfo/trx:StackTrace", nsMgr);