diff --git a/.reviewmark.yaml b/.reviewmark.yaml
index b4e3c43..24e0e31 100644
--- a/.reviewmark.yaml
+++ b/.reviewmark.yaml
@@ -44,7 +44,7 @@ reviews:
title: Review of All TestResults Requirements
paths:
- "requirements.yaml"
- - "docs/reqstream/**/*.yaml"
+ - "docs/reqstream/test-results/**/*.yaml"
- id: TestResults-IO
title: Review of TestResults IO Subsystem
diff --git a/docs/design/test-results/io/io.md b/docs/design/test-results/io/io.md
index 6df5801..6ab28e0 100644
--- a/docs/design/test-results/io/io.md
+++ b/docs/design/test-results/io/io.md
@@ -36,4 +36,4 @@ The IO subsystem depends on:
## Related Requirements
Requirements for the IO subsystem are in
-[docs/reqstream/test-results/io/](../../reqstream/test-results/io/).
+[docs/reqstream/test-results/io/](../../../reqstream/test-results/io/).
diff --git a/src/DemaConsulting.TestResults/TestOutcome.cs b/src/DemaConsulting.TestResults/TestOutcome.cs
index e041fc9..19c7cba 100644
--- a/src/DemaConsulting.TestResults/TestOutcome.cs
+++ b/src/DemaConsulting.TestResults/TestOutcome.cs
@@ -108,6 +108,7 @@ public static class TestOutcomeExtensions
/// True if the outcome indicates a pass
public static bool IsPassed(this TestOutcome outcome)
{
+ // Treat outcomes where the test logic completed without failure as passed
return outcome switch
{
TestOutcome.Passed => true,
@@ -124,6 +125,7 @@ public static bool IsPassed(this TestOutcome outcome)
/// True if the outcome indicates a fail
public static bool IsFailed(this TestOutcome outcome)
{
+ // Treat outcomes representing an abnormal termination or assertion failure as failed
return outcome switch
{
TestOutcome.Failed => true,
@@ -141,6 +143,7 @@ public static bool IsFailed(this TestOutcome outcome)
/// True if the outcome indicates the test was executed
public static bool IsExecuted(this TestOutcome outcome)
{
+ // Treat outcomes where the test was never attempted as not executed
return outcome switch
{
TestOutcome.NotRunnable => false,
diff --git a/src/DemaConsulting.TestResults/TestResult.cs b/src/DemaConsulting.TestResults/TestResult.cs
index a2de702..5db3a50 100644
--- a/src/DemaConsulting.TestResults/TestResult.cs
+++ b/src/DemaConsulting.TestResults/TestResult.cs
@@ -25,68 +25,92 @@ namespace DemaConsulting.TestResults;
///
public sealed class TestResult
{
+ // Identity properties — each result needs unique IDs for cross-referencing
+ // between the test definition and its execution record
+
///
- /// Gets or sets the ID of the test case
+ /// Gets or sets the ID of the test case.
+ /// Defaults to a newly generated so every test definition is uniquely identifiable.
///
public Guid TestId { get; set; } = Guid.NewGuid();
///
- /// Gets or sets the ID of the test execution
+ /// Gets or sets the ID of the test execution.
+ /// Defaults to a newly generated so every execution is uniquely identifiable.
///
public Guid ExecutionId { get; set; } = Guid.NewGuid();
+ // Descriptive metadata — human-readable strings that identify the test in reports
+
///
- /// Gets or sets the name of the test case
+ /// Gets or sets the name of the test case.
+ /// Defaults to so the property is always non-null.
///
public string Name { get; set; } = string.Empty;
///
- /// Gets or sets the test code assembly
+ /// Gets or sets the test code assembly.
+ /// Defaults to so the property is always non-null.
///
public string CodeBase { get; set; } = string.Empty;
///
- /// Gets or sets the name of the class containing the test case
+ /// Gets or sets the name of the class containing the test case.
+ /// Defaults to so the property is always non-null.
///
public string ClassName { get; set; } = string.Empty;
///
- /// Gets or sets the name of the computer that executed the test case
+ /// Gets or sets the name of the computer that executed the test case.
+ /// Defaults to so locally-run results are attributed correctly.
///
public string ComputerName { get; set; } = Environment.MachineName;
+ // Timing properties — record when and how long the test ran
+
///
- /// Gets or sets the start time of the test execution
+ /// Gets or sets the start time of the test execution.
+ /// Defaults to at construction time so ad-hoc results have a meaningful timestamp.
///
public DateTime StartTime { get; set; } = DateTime.UtcNow;
///
- /// Gets or sets the duration of the test execution
+ /// Gets or sets the duration of the test execution.
+ /// Defaults to so the property is always valid even when timing is unavailable.
///
public TimeSpan Duration { get; set; } = TimeSpan.Zero;
+ // Output capture — text written to stdout/stderr during the test run
+
///
- /// Gets or sets the stdout output when executing the test case
+ /// Gets or sets the stdout output when executing the test case.
+ /// Defaults to so the property is always non-null.
///
public string SystemOutput { get; set; } = string.Empty;
///
- /// Gets or sets the stderr output when executing the test case
+ /// Gets or sets the stderr output when executing the test case.
+ /// Defaults to so the property is always non-null.
///
public string SystemError { get; set; } = string.Empty;
+ // Result properties — the outcome and any failure details
+
///
- /// Gets or sets the outcome of the test case
+ /// Gets or sets the outcome of the test case.
+ /// Defaults to so a result that was never run is not mistaken for a pass.
///
public TestOutcome Outcome { get; set; } = TestOutcome.NotExecuted;
///
- /// Gets or sets the test case error message
+ /// Gets or sets the test case error message.
+ /// Defaults to so the property is always non-null.
///
public string ErrorMessage { get; set; } = string.Empty;
///
- /// Gets or sets the test case error stack trace
+ /// Gets or sets the test case error stack trace.
+ /// Defaults to so the property is always non-null.
///
public string ErrorStackTrace { get; set; } = string.Empty;
}
diff --git a/src/DemaConsulting.TestResults/TestResults.cs b/src/DemaConsulting.TestResults/TestResults.cs
index 5323c0b..80cd362 100644
--- a/src/DemaConsulting.TestResults/TestResults.cs
+++ b/src/DemaConsulting.TestResults/TestResults.cs
@@ -25,23 +25,31 @@ namespace DemaConsulting.TestResults;
///
public sealed class TestResults
{
+ // Identity and metadata — unique identifier and human-readable name for the run
+
///
- /// Gets or sets the ID of the test results
+ /// Gets or sets the ID of the test results.
+ /// Defaults to a newly generated so every test run is uniquely identifiable.
///
public Guid Id { get; set; } = Guid.NewGuid();
///
- /// Gets or sets the name of the tests
+ /// Gets or sets the name of the tests.
+ /// Defaults to so the property is always non-null.
///
public string Name { get; set; } = string.Empty;
///
- /// Gets or sets the name of the user account running the tests
+ /// Gets or sets the name of the user account running the tests.
+ /// Defaults to so the property is always non-null.
///
public string UserName { get; set; } = string.Empty;
+ // Results collection — the ordered list of individual test outcomes for this run
+
///
- /// Gets or sets the list containing each TestResult
+ /// Gets or sets the list containing each .
+ /// Defaults to an empty list so callers can add results without null-checking first.
///
public List Results { get; set; } = [];
}
diff --git a/test/DemaConsulting.TestResults.Tests/IO/JUnitSerializerTests.cs b/test/DemaConsulting.TestResults.Tests/IO/JUnitSerializerTests.cs
index f3bfc17..651ee83 100644
--- a/test/DemaConsulting.TestResults.Tests/IO/JUnitSerializerTests.cs
+++ b/test/DemaConsulting.TestResults.Tests/IO/JUnitSerializerTests.cs
@@ -151,7 +151,7 @@ public void JUnitSerializer_Serialize_FailedTest_IncludesFailureElement()
[TestMethod]
public void JUnitSerializer_Serialize_ErrorTest_IncludesErrorElement()
{
- // Construct test results with an error test
+ // Arrange - Construct test results with an error test
var results = new TestResults
{
Name = "ErrorTests",
@@ -169,11 +169,11 @@ public void JUnitSerializer_Serialize_ErrorTest_IncludesErrorElement()
]
};
- // Serialize the test results
+ // Act - Serialize the test results
var xml = JUnitSerializer.Serialize(results);
Assert.IsNotNull(xml);
- // Parse and verify the XML structure
+ // Assert - Parse and verify the XML structure
var doc = XDocument.Parse(xml);
var testSuite = doc.Root?.Element("testsuite");
Assert.IsNotNull(testSuite);
@@ -181,7 +181,7 @@ public void JUnitSerializer_Serialize_ErrorTest_IncludesErrorElement()
Assert.AreEqual("0", testSuite.Attribute("failures")?.Value);
Assert.AreEqual("1", testSuite.Attribute("errors")?.Value);
- // Verify test case with error
+ // Assert - Verify test case with error
var testCase = testSuite.Element("testcase");
Assert.IsNotNull(testCase);
var error = testCase.Element("error");
@@ -196,7 +196,7 @@ public void JUnitSerializer_Serialize_ErrorTest_IncludesErrorElement()
[TestMethod]
public void JUnitSerializer_Serialize_SkippedTest_IncludesSkippedElement()
{
- // Construct test results with a skipped test
+ // Arrange - Construct test results with a skipped test
var results = new TestResults
{
Name = "SkippedTests",
@@ -213,11 +213,11 @@ public void JUnitSerializer_Serialize_SkippedTest_IncludesSkippedElement()
]
};
- // Serialize the test results
+ // Act - Serialize the test results
var xml = JUnitSerializer.Serialize(results);
Assert.IsNotNull(xml);
- // Parse and verify the XML structure
+ // Assert - Parse and verify the XML structure
var doc = XDocument.Parse(xml);
var testSuite = doc.Root?.Element("testsuite");
Assert.IsNotNull(testSuite);
@@ -226,7 +226,7 @@ public void JUnitSerializer_Serialize_SkippedTest_IncludesSkippedElement()
Assert.AreEqual("0", testSuite.Attribute("errors")?.Value);
Assert.AreEqual("1", testSuite.Attribute("skipped")?.Value);
- // Verify test case with skipped element
+ // Assert - Verify test case with skipped element
var testCase = testSuite.Element("testcase");
Assert.IsNotNull(testCase);
var skipped = testCase.Element("skipped");
@@ -240,7 +240,7 @@ public void JUnitSerializer_Serialize_SkippedTest_IncludesSkippedElement()
[TestMethod]
public void JUnitSerializer_Serialize_TestWithOutput_IncludesSystemOutAndErr()
{
- // Construct test results with system output
+ // Arrange - Construct test results with system output
var results = new TestResults
{
Name = "OutputTests",
@@ -258,21 +258,21 @@ public void JUnitSerializer_Serialize_TestWithOutput_IncludesSystemOutAndErr()
]
};
- // Serialize the test results
+ // Act - Serialize the test results
var xml = JUnitSerializer.Serialize(results);
Assert.IsNotNull(xml);
- // Parse and verify the XML structure
+ // Assert - Parse and verify the XML structure
var doc = XDocument.Parse(xml);
var testCase = doc.Root?.Element("testsuite")?.Element("testcase");
Assert.IsNotNull(testCase);
- // Verify system-out element
+ // Assert - Verify system-out element
var systemOut = testCase.Element("system-out");
Assert.IsNotNull(systemOut);
Assert.AreEqual("Standard output message", systemOut.Value);
- // Verify system-err element
+ // Assert - Verify system-err element
var systemErr = testCase.Element("system-err");
Assert.IsNotNull(systemErr);
Assert.AreEqual("Standard error message", systemErr.Value);
@@ -284,7 +284,7 @@ public void JUnitSerializer_Serialize_TestWithOutput_IncludesSystemOutAndErr()
[TestMethod]
public void JUnitSerializer_Serialize_MultipleTestsInClasses_GroupsByClassName()
{
- // Construct test results with multiple tests
+ // Arrange - Construct test results with multiple tests
var results = new TestResults
{
Name = "MultipleTests",
@@ -315,27 +315,27 @@ public void JUnitSerializer_Serialize_MultipleTestsInClasses_GroupsByClassName()
]
};
- // Serialize the test results
+ // Act - Serialize the test results
var xml = JUnitSerializer.Serialize(results);
Assert.IsNotNull(xml);
- // Parse and verify the XML structure
+ // Assert - Parse and verify the XML structure
var doc = XDocument.Parse(xml);
var root = doc.Root;
Assert.IsNotNull(root);
- // Verify two test suites (one for each class)
+ // Assert - Verify two test suites (one for each class)
var testSuites = root.Elements("testsuite").ToList();
Assert.HasCount(2, testSuites);
- // Verify first test suite (Class1)
+ // Assert - Verify first test suite (Class1)
var suite1 = testSuites[0];
Assert.AreEqual("Class1", suite1.Attribute("name")?.Value);
Assert.AreEqual("2", suite1.Attribute("tests")?.Value);
Assert.AreEqual("1", suite1.Attribute("failures")?.Value);
Assert.AreEqual("1.500", suite1.Attribute("time")?.Value);
- // Verify second test suite (Class2)
+ // Assert - Verify second test suite (Class2)
var suite2 = testSuites[1];
Assert.AreEqual("Class2", suite2.Attribute("name")?.Value);
Assert.AreEqual("1", suite2.Attribute("tests")?.Value);
@@ -349,7 +349,7 @@ public void JUnitSerializer_Serialize_MultipleTestsInClasses_GroupsByClassName()
[TestMethod]
public void JUnitSerializer_Serialize_EmptyClassName_UsesDefaultSuite()
{
- // Construct test results with empty class name
+ // Arrange - Construct test results with empty class name
var results = new TestResults
{
Name = "EmptyClassTests",
@@ -365,11 +365,11 @@ public void JUnitSerializer_Serialize_EmptyClassName_UsesDefaultSuite()
]
};
- // Serialize the test results
+ // Act - Serialize the test results
var xml = JUnitSerializer.Serialize(results);
Assert.IsNotNull(xml);
- // Parse and verify the XML structure
+ // Assert - Parse and verify the XML structure
var doc = XDocument.Parse(xml);
var testSuite = doc.Root?.Element("testsuite");
Assert.IsNotNull(testSuite);
@@ -386,10 +386,10 @@ public void JUnitSerializer_Serialize_EmptyClassName_UsesDefaultSuite()
[TestMethod]
public void JUnitSerializer_Serialize_UsageExample_ProducesValidJUnitXml()
{
- // Create a TestResults instance matching the usage example
+ // Arrange - Create a TestResults instance matching the usage example
var results = new TestResults { Name = "SomeTests" };
- // Add some results
+ // Arrange - Add some results
results.Results.Add(
new TestResult
{
@@ -412,34 +412,34 @@ public void JUnitSerializer_Serialize_UsageExample_ProducesValidJUnitXml()
ErrorStackTrace = "at SomeTestClass.Test2() in Test.cs:line 15"
});
- // Serialize the results
+ // Act - Serialize the results
var xml = JUnitSerializer.Serialize(results);
Assert.IsNotNull(xml);
- // Parse and verify the structure matches expected JUnit format
+ // Assert - Parse and verify the structure matches expected JUnit format
var doc = XDocument.Parse(xml);
var root = doc.Root;
Assert.IsNotNull(root);
Assert.AreEqual("testsuites", root.Name.LocalName);
Assert.AreEqual("SomeTests", root.Attribute("name")?.Value);
- // Verify test suite
+ // Assert - Verify test suite
var testSuite = root.Element("testsuite");
Assert.IsNotNull(testSuite);
Assert.AreEqual("SomeTestClass", testSuite.Attribute("name")?.Value);
Assert.AreEqual("2", testSuite.Attribute("tests")?.Value);
Assert.AreEqual("1", testSuite.Attribute("failures")?.Value);
- // Verify both test cases are present
+ // Assert - Verify both test cases are present
var testCases = testSuite.Elements("testcase").ToList();
Assert.HasCount(2, testCases);
- // Verify passed test
+ // Assert - Verify passed test
var passedTest = testCases.FirstOrDefault(tc => tc.Attribute("name")?.Value == "Test1");
Assert.IsNotNull(passedTest);
Assert.IsNull(passedTest.Element("failure"));
- // Verify failed test
+ // Assert - Verify failed test
var failedTest = testCases.FirstOrDefault(tc => tc.Attribute("name")?.Value == "Test2");
Assert.IsNotNull(failedTest);
var failure = failedTest.Element("failure");
@@ -490,7 +490,7 @@ public void JUnitSerializer_Deserialize_BasicJUnitXml_ReturnsTestResults()
[TestMethod]
public void JUnitSerializer_Deserialize_FailedTest_ReturnsFailureDetails()
{
- // Deserialize the test results object with a failed test
+ // Arrange and Act - Deserialize the test results object with a failed test
var results = JUnitSerializer.Deserialize(
"""
@@ -504,11 +504,11 @@ public void JUnitSerializer_Deserialize_FailedTest_ReturnsFailureDetails()
""");
Assert.IsNotNull(results);
- // Assert results information
+ // Assert - Verify results information
Assert.AreEqual("FailureTests", results.Name);
Assert.HasCount(1, results.Results);
- // Assert test result information
+ // Assert - Verify test result information
var result = results.Results[0];
Assert.AreEqual("Test2", result.Name);
Assert.AreEqual("MyTestClass", result.ClassName);
@@ -523,7 +523,7 @@ public void JUnitSerializer_Deserialize_FailedTest_ReturnsFailureDetails()
[TestMethod]
public void JUnitSerializer_Deserialize_ErrorTest_ReturnsErrorDetails()
{
- // Deserialize the test results object with an error test
+ // Arrange and Act - Deserialize the test results object with an error test
var results = JUnitSerializer.Deserialize(
"""
@@ -537,7 +537,7 @@ public void JUnitSerializer_Deserialize_ErrorTest_ReturnsErrorDetails()
""");
Assert.IsNotNull(results);
- // Assert test result information
+ // Assert - Verify test result information
var result = results.Results[0];
Assert.AreEqual("Test3", result.Name);
Assert.AreEqual(TestOutcome.Error, result.Outcome);
@@ -551,7 +551,7 @@ public void JUnitSerializer_Deserialize_ErrorTest_ReturnsErrorDetails()
[TestMethod]
public void JUnitSerializer_Deserialize_SkippedTest_ReturnsSkippedStatus()
{
- // Deserialize the test results object with a skipped test
+ // Arrange and Act - Deserialize the test results object with a skipped test
var results = JUnitSerializer.Deserialize(
"""
@@ -565,7 +565,7 @@ public void JUnitSerializer_Deserialize_SkippedTest_ReturnsSkippedStatus()
""");
Assert.IsNotNull(results);
- // Assert test result information
+ // Assert - Verify test result information
var result = results.Results[0];
Assert.AreEqual("Test4", result.Name);
Assert.AreEqual(TestOutcome.NotExecuted, result.Outcome);
@@ -578,7 +578,7 @@ public void JUnitSerializer_Deserialize_SkippedTest_ReturnsSkippedStatus()
[TestMethod]
public void JUnitSerializer_Deserialize_TestWithOutput_ReturnsSystemOutput()
{
- // Deserialize the test results object with system output
+ // Arrange and Act - Deserialize the test results object with system output
var results = JUnitSerializer.Deserialize(
"""
@@ -593,7 +593,7 @@ public void JUnitSerializer_Deserialize_TestWithOutput_ReturnsSystemOutput()
""");
Assert.IsNotNull(results);
- // Assert test result information
+ // Assert - Verify test result information
var result = results.Results[0];
Assert.AreEqual("Test5", result.Name);
Assert.AreEqual("Standard output message", result.SystemOutput);
@@ -606,7 +606,7 @@ public void JUnitSerializer_Deserialize_TestWithOutput_ReturnsSystemOutput()
[TestMethod]
public void JUnitSerializer_Deserialize_MultipleTestSuites_ReturnsAllTests()
{
- // Deserialize the test results object with multiple test suites
+ // Arrange and Act - Deserialize the test results object with multiple test suites
var results = JUnitSerializer.Deserialize(
"""
@@ -624,22 +624,22 @@ public void JUnitSerializer_Deserialize_MultipleTestSuites_ReturnsAllTests()
""");
Assert.IsNotNull(results);
- // Assert results information
+ // Assert - Verify results information
Assert.AreEqual("MultipleTests", results.Name);
Assert.HasCount(3, results.Results);
- // Verify first test
+ // Assert - Verify first test
var test1 = results.Results[0];
Assert.AreEqual("Test1", test1.Name);
Assert.AreEqual("Class1", test1.ClassName);
Assert.AreEqual(TestOutcome.Passed, test1.Outcome);
- // Verify second test
+ // Assert - Verify second test
var test2 = results.Results[1];
Assert.AreEqual("Test2", test2.Name);
Assert.AreEqual(TestOutcome.Failed, test2.Outcome);
- // Verify third test
+ // Assert - Verify third test
var test3 = results.Results[2];
Assert.AreEqual("Test3", test3.Name);
Assert.AreEqual("Class2", test3.ClassName);
@@ -652,7 +652,7 @@ public void JUnitSerializer_Deserialize_MultipleTestSuites_ReturnsAllTests()
[TestMethod]
public void JUnitSerializer_Deserialize_DefaultSuite_ReturnsEmptyClassName()
{
- // Deserialize the test results object with DefaultSuite
+ // Arrange and Act - Deserialize the test results object with DefaultSuite
var results = JUnitSerializer.Deserialize(
"""
@@ -664,7 +664,7 @@ public void JUnitSerializer_Deserialize_DefaultSuite_ReturnsEmptyClassName()
""");
Assert.IsNotNull(results);
- // Assert test result information - DefaultSuite should be converted to empty string
+ // Assert - Verify test result information - DefaultSuite should be converted to empty string
var result = results.Results[0];
Assert.AreEqual("Test1", result.Name);
Assert.AreEqual(string.Empty, result.ClassName);
@@ -737,7 +737,7 @@ public void JUnitSerializer_Serialize_ThenDeserialize_PreservesTestData()
[TestMethod]
public void JUnitSerializer_Deserialize_MissingTimeAttribute_DefaultsToZero()
{
- // Deserialize the test results object without time attribute
+ // Arrange and Act - Deserialize the test results object without time attribute
var results = JUnitSerializer.Deserialize(
"""
diff --git a/test/DemaConsulting.TestResults.Tests/TestOutcomeTests.cs b/test/DemaConsulting.TestResults.Tests/TestOutcomeTests.cs
index ea63099..76b6dcf 100644
--- a/test/DemaConsulting.TestResults.Tests/TestOutcomeTests.cs
+++ b/test/DemaConsulting.TestResults.Tests/TestOutcomeTests.cs
@@ -34,6 +34,9 @@ public class TestOutcomeTests
[TestMethod]
public void TestOutcome_IsPassed_PassedOutcome_ReturnsTrue()
{
+ // Arrange - no setup required; testing enum extension directly
+
+ // Act and Assert - verify each outcome returns the expected IsPassed result
Assert.IsFalse(TestOutcome.Error.IsPassed());
Assert.IsFalse(TestOutcome.Failed.IsPassed());
Assert.IsFalse(TestOutcome.Timeout.IsPassed());
@@ -56,6 +59,9 @@ public void TestOutcome_IsPassed_PassedOutcome_ReturnsTrue()
[TestMethod]
public void TestOutcome_IsFailed_FailedOutcome_ReturnsTrue()
{
+ // Arrange - no setup required; testing enum extension directly
+
+ // Act and Assert - verify each outcome returns the expected IsFailed result
Assert.IsTrue(TestOutcome.Error.IsFailed());
Assert.IsTrue(TestOutcome.Failed.IsFailed());
Assert.IsTrue(TestOutcome.Timeout.IsFailed());
@@ -78,6 +84,9 @@ public void TestOutcome_IsFailed_FailedOutcome_ReturnsTrue()
[TestMethod]
public void TestOutcome_IsExecuted_AllOutcomes_ReturnsExpectedResult()
{
+ // Arrange - no setup required; testing enum extension directly
+
+ // Act and Assert - verify each outcome returns the expected IsExecuted result
Assert.IsTrue(TestOutcome.Error.IsExecuted());
Assert.IsTrue(TestOutcome.Failed.IsExecuted());
Assert.IsTrue(TestOutcome.Timeout.IsExecuted());
@@ -100,6 +109,9 @@ public void TestOutcome_IsExecuted_AllOutcomes_ReturnsExpectedResult()
[TestMethod]
public void TestOutcome_IsExecuted_NotExecutedOutcome_ReturnsFalse()
{
+ // Arrange - no setup required; testing enum extension directly
+
+ // Act and Assert - verify NotExecuted outcome returns false
Assert.IsFalse(TestOutcome.NotExecuted.IsExecuted());
}
}