diff --git a/TcUnit-Runner/TcUnitResultCollector.cs b/TcUnit-Runner/TcUnitResultCollector.cs index 535d02e..a5a00ef 100644 --- a/TcUnit-Runner/TcUnitResultCollector.cs +++ b/TcUnit-Runner/TcUnitResultCollector.cs @@ -15,9 +15,10 @@ class TcUnitResultCollector private enum ErrorLogEntryType { TEST_SUITE_FINISHED_RUNNING = 0, // For example: | Test suite ID=1 'PRG_TEST.fbDiagnosticMessageFlagsParser_Test' - TEST_SUITE_STATISTICS, // For example: | ID=1 number of tests=4, number of failed tests=1 + TEST_SUITE_STATISTICS, // For example: | ID=1 number of tests=4, number of failed tests=1, duration=0.1 TEST_NAME, // For example: | Test name=WhenWarningMessageExpectWarningMessageLocalTimestampAndTwoParameters TEST_CLASS_NAME, // For example: | Test class name=PRG_TEST.fbDiagnosticMessageFlagsParser_Test + TEST_DURATION, // For example: | Test duration=0.010 TEST_STATUS_AND_NUMBER_OF_ASSERTS, // For example: | Test status=SUCCESS, number of asserts=3 TEST_ASSERT_MESSAGE, // For example: | Test assert message=Test 'Warning message' failed at 'diagnosis type' TEST_ASSERT_TYPE, // For example: | Test assert type=ANY @@ -27,11 +28,12 @@ private enum ErrorLogEntryType private int numberOfTests = -1; private int numberOfSuccessfulTests = -1; private int numberOfFailedTests = -1; + private double duration = 0.0; private const string tcUnitResult_TestSuites = "| Test suites:"; private const string tcUnitResult_Tests = "| Tests:"; private const string tcUnitResult_SuccessfulTests = "| Successful tests:"; private const string tcUnitResult_FailedTests = "| Failed tests:"; - + private const string tcUnitResult_Duration = "| Duration:"; public TcUnitResultCollector() { } @@ -73,6 +75,11 @@ public bool AreResultsAvailable(ErrorItems errorItems) string noFailedTests = line.Substring(line.LastIndexOf(tcUnitResult_FailedTests) + tcUnitResult_FailedTests.Length + 1); Int32.TryParse(noFailedTests, out numberOfFailedTests); } + if (line.Contains(tcUnitResult_Duration)) + { + string durationString = line.Substring(line.LastIndexOf(tcUnitResult_Duration) + tcUnitResult_Duration.Length + 1); + double.TryParse(durationString, out duration); + } } return AreTestResultsAvailable(); } @@ -97,7 +104,8 @@ public TcUnitTestResult ParseResults(IEnumerable errors, string ErrorLogEntryType expectedErrorLogEntryType = ErrorLogEntryType.TEST_SUITE_FINISHED_RUNNING; tcUnitTestResult.AddGeneralTestResults((uint)numberOfTestSuites, (uint)numberOfTests, - (uint)numberOfSuccessfulTests, (uint)numberOfFailedTests); + (uint)numberOfSuccessfulTests, (uint)numberOfFailedTests, + duration); // Temporary variables uint currentTestIdentity = 0; @@ -109,10 +117,12 @@ public TcUnitTestResult ParseResults(IEnumerable errors, string uint testSuiteIdentity = 0; uint testSuiteNumberOfTests = 0; uint testSuiteNumberOfFailedTests = 0; + double testSuiteDuration = 0.0; // Test case string testSuiteTestCaseName = ""; string testSuiteTestCaseClassName = ""; + double testSuiteTestCaseDuration = 0.0; string testSuiteTestCaseStatus = ""; string testSuiteTestCaseFailureMessage = ""; string testSuiteTestCaseAssertType = ""; @@ -139,9 +149,11 @@ public TcUnitTestResult ParseResults(IEnumerable errors, string testSuiteIdentity = 0; testSuiteNumberOfTests = 0; testSuiteNumberOfFailedTests = 0; + testSuiteDuration = 0.0; testSuiteTestCaseName = ""; testSuiteTestCaseClassName = ""; + testSuiteTestCaseDuration = 0.0; testSuiteTestCaseStatus = ""; testSuiteTestCaseFailureMessage = ""; testSuiteTestCaseAssertType = ""; @@ -178,11 +190,16 @@ public TcUnitTestResult ParseResults(IEnumerable errors, string { // Handle error } - string numberOfFailedTestsString = tcUnitAdsMessage.Substring(tcUnitAdsMessage.LastIndexOf(", number of failed tests=") + 25); + string numberOfFailedTestsString = Utilities.GetStringBetween(tcUnitAdsMessage, ", number of failed tests=", ", duration="); if (!uint.TryParse(numberOfFailedTestsString, out testSuiteNumberOfFailedTests)) { // Handle error } + string durationString = tcUnitAdsMessage.Substring(tcUnitAdsMessage.LastIndexOf(", duration=") + 11); + if (!double.TryParse(durationString, out testSuiteDuration)) + { + // Handle error + } /* Now two things can happen. Either the testsuite didn't have any tests (testSuiteNumberOfTests=0) or it had tests. If it didn't have any tests, we store the testsuite result here and go to the @@ -191,7 +208,7 @@ public TcUnitTestResult ParseResults(IEnumerable errors, string if (testSuiteNumberOfTests.Equals(0)) { // Store test suite & go to next test suite - TcUnitTestResult.TestSuiteResult tsResult = new TcUnitTestResult.TestSuiteResult(testSuiteName, testSuiteIdentity, testSuiteNumberOfTests, testSuiteNumberOfFailedTests); + TcUnitTestResult.TestSuiteResult tsResult = new TcUnitTestResult.TestSuiteResult(testSuiteName, testSuiteIdentity, testSuiteNumberOfTests, testSuiteNumberOfFailedTests, testSuiteDuration); tcUnitTestResult.AddNewTestSuiteResult(tsResult); expectedErrorLogEntryType = ErrorLogEntryType.TEST_SUITE_FINISHED_RUNNING; } @@ -243,6 +260,28 @@ public TcUnitTestResult ParseResults(IEnumerable errors, string // Parse test class name string testClassName = tcUnitAdsMessage.Substring(tcUnitAdsMessage.LastIndexOf("Test class name=") + 16); testSuiteTestCaseClassName = testClassName; + expectedErrorLogEntryType = ErrorLogEntryType.TEST_DURATION; + } + else + { + log.Error("While parsing TcUnit results, expected " + expectedErrorLogEntryType.ToString() + " but got " + ErrorLogEntryType.TEST_CLASS_NAME.ToString()); + return null; + } + } + + /* ------------------------------------- + Look for test duration + ------------------------------------- */ + else if (tcUnitAdsMessage.Contains("Test duration=")) + { + if (expectedErrorLogEntryType == ErrorLogEntryType.TEST_DURATION) + { + // Parse test class name + string testDuration = tcUnitAdsMessage.Substring(tcUnitAdsMessage.LastIndexOf("Test duration=") + 14); + if (!double.TryParse(testDuration, out testSuiteTestCaseDuration)) + { + // Handle error + } expectedErrorLogEntryType = ErrorLogEntryType.TEST_STATUS_AND_NUMBER_OF_ASSERTS; } else @@ -276,7 +315,7 @@ or the next test suite */ else { // Store test case - TcUnitTestResult.TestCaseResult tcResult = new TcUnitTestResult.TestCaseResult(testSuiteTestCaseName, testSuiteTestCaseClassName, testSuiteTestCaseStatus, "", "", testSuiteTestCaseNumberOfAsserts); + TcUnitTestResult.TestCaseResult tcResult = new TcUnitTestResult.TestCaseResult(testSuiteTestCaseName, testSuiteTestCaseClassName, testSuiteTestCaseStatus, "", "", testSuiteTestCaseNumberOfAsserts, testSuiteTestCaseDuration); // Add test case result to test cases results testSuiteTestCaseResults.Add(tcResult); @@ -288,7 +327,7 @@ or the next test suite */ else { // Last test case in this test suite // Create test suite result - TcUnitTestResult.TestSuiteResult tsResult = new TcUnitTestResult.TestSuiteResult(testSuiteName, testSuiteIdentity, testSuiteNumberOfTests, testSuiteNumberOfFailedTests); + TcUnitTestResult.TestSuiteResult tsResult = new TcUnitTestResult.TestSuiteResult(testSuiteName, testSuiteIdentity, testSuiteNumberOfTests, testSuiteNumberOfFailedTests, testSuiteDuration); // Add test case results to test suite foreach (TcUnitTestResult.TestCaseResult tcResultToBeStored in testSuiteTestCaseResults) @@ -301,7 +340,6 @@ or the next test suite */ expectedErrorLogEntryType = ErrorLogEntryType.TEST_SUITE_FINISHED_RUNNING; } } - } else { @@ -350,7 +388,7 @@ or the next test suite */ testSuiteTestCaseAssertType = testAssertType; // Store test case - TcUnitTestResult.TestCaseResult tcResult = new TcUnitTestResult.TestCaseResult(testSuiteTestCaseName, testSuiteTestCaseClassName, testSuiteTestCaseStatus, testSuiteTestCaseFailureMessage, testSuiteTestCaseAssertType, testSuiteTestCaseNumberOfAsserts); + TcUnitTestResult.TestCaseResult tcResult = new TcUnitTestResult.TestCaseResult(testSuiteTestCaseName, testSuiteTestCaseClassName, testSuiteTestCaseStatus, testSuiteTestCaseFailureMessage, testSuiteTestCaseAssertType, testSuiteTestCaseNumberOfAsserts, testSuiteTestCaseDuration); // Add test case result to test cases results testSuiteTestCaseResults.Add(tcResult); @@ -362,7 +400,7 @@ or the next test suite */ else { // Last test case in this test suite // Create test suite result - TcUnitTestResult.TestSuiteResult tsResult = new TcUnitTestResult.TestSuiteResult(testSuiteName, testSuiteIdentity, testSuiteNumberOfTests, testSuiteNumberOfFailedTests); + TcUnitTestResult.TestSuiteResult tsResult = new TcUnitTestResult.TestSuiteResult(testSuiteName, testSuiteIdentity, testSuiteNumberOfTests, testSuiteNumberOfFailedTests, testSuiteTestCaseDuration); // Add test case results to test suite foreach (TcUnitTestResult.TestCaseResult tcResultToBeStored in testSuiteTestCaseResults) diff --git a/TcUnit-Runner/TcUnitTestResult.cs b/TcUnit-Runner/TcUnitTestResult.cs index def5f39..f34ac66 100644 --- a/TcUnit-Runner/TcUnitTestResult.cs +++ b/TcUnit-Runner/TcUnitTestResult.cs @@ -11,6 +11,7 @@ class TcUnitTestResult : IEnumerable, IEnumera protected uint _numberOfTestCases; protected uint _numberOfSuccessfulTestCases; protected uint _numberOfFailedTestCases; + protected double _duration; /* Test results for each individiual test suite */ protected List _testSuiteResults = new List(); @@ -73,11 +74,13 @@ public struct TestCaseResult public string FailureMessage; public string AssertType; public uint NumberOfAsserts; + public double TestDuration; public bool WasSuccessful; - public TestCaseResult(string testName, string testClassName, string testStatus, string failureMessage, string assertType, uint numberOfAsserts) + public TestCaseResult(string testName, string testClassName, string testStatus, string failureMessage, string assertType, uint numberOfAsserts, double duration) { TestName = testName; TestClassName = testClassName; + TestDuration = duration; TestStatus = testStatus; FailureMessage = failureMessage; AssertType = assertType; @@ -92,14 +95,16 @@ public struct TestSuiteResult public uint Identity; public uint NumberOfTests; public uint NumberOfFailedTests; + public double Duration; public List TestCaseResults; - public TestSuiteResult(string name, uint identity, uint numberOfTests, uint numberOfFailedTests) + public TestSuiteResult(string name, uint identity, uint numberOfTests, uint numberOfFailedTests, double duration) { Name = name; Identity = identity; NumberOfTests = numberOfTests; NumberOfFailedTests = numberOfFailedTests; + Duration = duration; TestCaseResults = new List(); } } @@ -109,12 +114,13 @@ public void AddNewTestSuiteResult(TestSuiteResult testsuiteResult) _testSuiteResults.Add(testsuiteResult); } - public void AddGeneralTestResults(uint numberOfTestSuites, uint numberOfTestCases, uint numberOfSuccessfulTestCases, uint numberOfFailedTestCases) + public void AddGeneralTestResults(uint numberOfTestSuites, uint numberOfTestCases, uint numberOfSuccessfulTestCases, uint numberOfFailedTestCases, double duration) { _numberOfTestSuites = numberOfTestSuites; _numberOfTestCases = numberOfTestCases; _numberOfSuccessfulTestCases = numberOfSuccessfulTestCases; _numberOfFailedTestCases = numberOfFailedTestCases; + _duration = duration; } IEnumerator IEnumerable.GetEnumerator() @@ -146,6 +152,10 @@ public uint GetNumberOfFailedTestCases() { return _numberOfFailedTestCases; } + public double GetDuration() + { + return _duration; + } public bool GetAllTestsPassed() { diff --git a/TcUnit-Runner/XunitXmlCreator.cs b/TcUnit-Runner/XunitXmlCreator.cs index 6218f90..2bb89e0 100644 --- a/TcUnit-Runner/XunitXmlCreator.cs +++ b/TcUnit-Runner/XunitXmlCreator.cs @@ -34,6 +34,9 @@ public static void WriteXml(TcUnitTestResult testResults, string filePath) XmlAttribute testSuitesAttributeTests = xmlDoc.CreateAttribute("tests"); testSuitesAttributeTests.Value = testResults.GetNumberOfTestCases().ToString(); testSuitesNode.Attributes.Append(testSuitesAttributeTests); + XmlAttribute testSuitesAttributeTime = xmlDoc.CreateAttribute("time"); + testSuitesAttributeTime.Value = testResults.GetDuration().ToString(); + testSuitesNode.Attributes.Append(testSuitesAttributeTests); foreach (TcUnitTestResult.TestSuiteResult tsResult in testResults) { @@ -52,6 +55,9 @@ public static void WriteXml(TcUnitTestResult testResults, string filePath) XmlAttribute testSuiteAttributeFailures = xmlDoc.CreateAttribute("failures"); testSuiteAttributeFailures.Value = tsResult.NumberOfFailedTests.ToString(); testSuiteNode.Attributes.Append(testSuiteAttributeFailures); + XmlAttribute testSuiteAttributeTime = xmlDoc.CreateAttribute("time"); + testSuiteAttributeTime.Value = tsResult.Duration.ToString(); + testSuiteNode.Attributes.Append(testSuiteAttributeTime); // foreach (TcUnitTestResult.TestCaseResult tcResult in tsResult.TestCaseResults) @@ -68,6 +74,9 @@ public static void WriteXml(TcUnitTestResult testResults, string filePath) XmlAttribute testCaseAttributeTestClassName = xmlDoc.CreateAttribute("classname"); testCaseAttributeTestClassName.Value = tcResult.TestClassName; testCaseNode.Attributes.Append(testCaseAttributeTestClassName); + XmlAttribute testCaseAttributeTestTime = xmlDoc.CreateAttribute("time"); + testCaseAttributeTestTime.Value = tcResult.TestDuration.ToString(); + testCaseNode.Attributes.Append(testCaseAttributeTestTime); XmlAttribute testCaseAttributeStatus = xmlDoc.CreateAttribute("status"); testCaseAttributeStatus.Value = tcResult.TestStatus; testCaseNode.Attributes.Append(testCaseAttributeStatus);