From 2b7deb90191d60d88881b7caa8aacd2f9a5c2c51 Mon Sep 17 00:00:00 2001 From: smolchanovsky Date: Tue, 20 Dec 2022 12:56:28 +0300 Subject: [PATCH 1/5] Add parameters to allure report --- Allure.XUnit/AllureXunitHelper.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Allure.XUnit/AllureXunitHelper.cs b/Allure.XUnit/AllureXunitHelper.cs index 05bc3b98..9d903752 100644 --- a/Allure.XUnit/AllureXunitHelper.cs +++ b/Allure.XUnit/AllureXunitHelper.cs @@ -59,7 +59,14 @@ public static void StartTestCase(ITestCaseMessage testCaseMessage) Label.TestClass(testCase.TestMethod.TestClass.Class.Name), Label.TestMethod(testCase.DisplayName), Label.Package(testCase.TestMethod.TestClass.Class.Name) - } + }, + parameters = testCase.TestMethod.Method.GetParameters() + .Zip(testCase.TestMethodArguments ?? Array.Empty(), (param, value) => new Parameter + { + name = param.Name, + value = value?.ToString() ?? "null" + }) + .ToList() }; UpdateTestDataFromAttributes(testResults.TestResult, testCase); AllureLifecycle.Instance.StartTestCase(testResults.TestResultContainer.uuid, testResults.TestResult); From 74c8a0f1e5d333a2a120af15bf1f2c188f4351ee Mon Sep 17 00:00:00 2001 From: smolchanovsky Date: Tue, 20 Dec 2022 12:56:56 +0300 Subject: [PATCH 2/5] Add allure attributes for names --- Allure.XUnit/AllureNameFormatter.cs | 24 +++++++++++++++++++ Allure.XUnit/AllureXunitHelper.cs | 11 +++++++-- .../Attributes/AllureFullNameAttribute.cs | 22 +++++++++++++++++ .../Attributes/AllureNameAttribute.cs | 22 +++++++++++++++++ 4 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 Allure.XUnit/AllureNameFormatter.cs create mode 100644 Allure.XUnit/Attributes/AllureFullNameAttribute.cs create mode 100644 Allure.XUnit/Attributes/AllureNameAttribute.cs diff --git a/Allure.XUnit/AllureNameFormatter.cs b/Allure.XUnit/AllureNameFormatter.cs new file mode 100644 index 00000000..b8e32d28 --- /dev/null +++ b/Allure.XUnit/AllureNameFormatter.cs @@ -0,0 +1,24 @@ +using System; +using System.Linq; +using Allure.Net.Commons; + +namespace Allure.XUnit +{ + public class AllureNameFormatter + { + private static readonly Func[] Formatters = { + (nameTemplate, testResult) => nameTemplate.Replace( + oldValue: "{params}", + newValue: string.Join(", ", testResult.parameters.Select(x => $"{x.name}"))), + + (nameTemplate, testResult) => nameTemplate.Replace( + oldValue: "{args}", + newValue: string.Join(", ", testResult.parameters.Select(x => $"{x.name}: {x.value}"))), + }; + + public static string Format(string nameTemplate, TestResult testResult) + { + return Formatters.Aggregate(nameTemplate, (current, formatter) => formatter(current, testResult)); + } + } +} \ No newline at end of file diff --git a/Allure.XUnit/AllureXunitHelper.cs b/Allure.XUnit/AllureXunitHelper.cs index 9d903752..ee487bc2 100644 --- a/Allure.XUnit/AllureXunitHelper.cs +++ b/Allure.XUnit/AllureXunitHelper.cs @@ -226,11 +226,18 @@ private static void UpdateTestDataFromAttributes(TestResult testResult, ITestCas testResult.labels.AddDistinct("story", storyAttribute.Stories, storyAttribute.Overwrite); break; + case AllureNameAttribute nameAttribute: + nameAttribute.UpdateTestResult(testResult); + break; + + case AllureFullNameAttribute fullNameAttribute: + fullNameAttribute.UpdateTestResult(testResult); + break; + case AllureDescriptionAttribute descriptionAttribute: testResult.description = descriptionAttribute.Description; break; - - + case AllureIdAttribute allureIdAttribute: var allureIdLabel = new Label {name = "ALLURE_ID", value = allureIdAttribute.AllureId}; testResult.labels.AddDistinct(allureIdLabel, false); diff --git a/Allure.XUnit/Attributes/AllureFullNameAttribute.cs b/Allure.XUnit/Attributes/AllureFullNameAttribute.cs new file mode 100644 index 00000000..8f270ea4 --- /dev/null +++ b/Allure.XUnit/Attributes/AllureFullNameAttribute.cs @@ -0,0 +1,22 @@ +using System; +using Allure.Net.Commons; +using Allure.XUnit; + +namespace Allure.Xunit.Attributes +{ + [AttributeUsage(AttributeTargets.Method)] + public class AllureFullNameAttribute : Attribute, IAllureInfo + { + public AllureFullNameAttribute(string fullName) + { + FullName = fullName ?? throw new ArgumentNullException(nameof(fullName)); + } + + internal string FullName { get; } + + internal void UpdateTestResult(TestResult testResult) + { + testResult.fullName = AllureNameFormatter.Format(FullName, testResult); + } + } +} \ No newline at end of file diff --git a/Allure.XUnit/Attributes/AllureNameAttribute.cs b/Allure.XUnit/Attributes/AllureNameAttribute.cs new file mode 100644 index 00000000..4ebdcb8b --- /dev/null +++ b/Allure.XUnit/Attributes/AllureNameAttribute.cs @@ -0,0 +1,22 @@ +using System; +using Allure.Net.Commons; +using Allure.XUnit; + +namespace Allure.Xunit.Attributes +{ + [AttributeUsage(AttributeTargets.Method)] + public class AllureNameAttribute : Attribute, IAllureInfo + { + public AllureNameAttribute(string name) + { + Name = name ?? throw new ArgumentNullException(nameof(name)); + } + + internal string Name { get; } + + internal void UpdateTestResult(TestResult testResult) + { + testResult.name = AllureNameFormatter.Format(Name, testResult); + } + } +} \ No newline at end of file From a6b79c769e8b08b04e906deac4ca7f462a479b01 Mon Sep 17 00:00:00 2001 From: smolchanovsky Date: Tue, 20 Dec 2022 12:57:15 +0300 Subject: [PATCH 3/5] Add example with random data --- .../ExampleParameterisedTests.cs | 14 +++++++++++++ .../TestData/TestDataGenerators.cs | 20 +++++++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/Allure.XUnit.Examples/ExampleParameterisedTests.cs b/Allure.XUnit.Examples/ExampleParameterisedTests.cs index 277f3f08..7fbbe33e 100644 --- a/Allure.XUnit.Examples/ExampleParameterisedTests.cs +++ b/Allure.XUnit.Examples/ExampleParameterisedTests.cs @@ -59,5 +59,19 @@ public void TestTheoryWithMemberData(MyTestClass a, MyTestClass b) { Assert.Equal(a.Test, b.Test); } + + [AllureXunitTheory] + [AllureName(nameof(TestTheoryWithMemberDataThatReturnsRandomData))] + [AllureFullName(nameof(TestTheoryWithMemberDataThatReturnsRandomData))] + [AllureParentSuite("AllTests")] + [AllureSuite("Test AllureXunitTheory")] + [AllureSubSuite("Test Test MemberData with random data")] + [MemberData(nameof(TestDataGenerators.RandomData), MemberType = typeof(TestDataGenerators))] + public void TestTheoryWithMemberDataThatReturnsRandomData(int value1, int value2, int expected) + { + var result = value1 + value2; + + Assert.Equal(expected, result); + } } } diff --git a/Allure.XUnit.Examples/TestData/TestDataGenerators.cs b/Allure.XUnit.Examples/TestData/TestDataGenerators.cs index e77d1bbf..7ce47ff9 100644 --- a/Allure.XUnit.Examples/TestData/TestDataGenerators.cs +++ b/Allure.XUnit.Examples/TestData/TestDataGenerators.cs @@ -1,9 +1,14 @@ +using System; using System.Collections.Generic; +using System.Linq; namespace Allure.XUnit.Examples.TestData { public class TestDataGenerators { + private static readonly object SyncLock = new(); + private static readonly Random Random = new(); + public static IEnumerable Data => new List { @@ -21,5 +26,20 @@ public class TestDataGenerators new object[] {new MyTestClass {Test = 10}, new MyTestClass {Test = 11}} }; + public static IEnumerable RandomData => + Enumerable.Range(0, 4).Select(_ => CreateTestData()); + + private static object[] CreateTestData() + { + return new object[] {GetRandomNumber(), GetRandomNumber(), GetRandomNumber()}; + } + + private static int GetRandomNumber() + { + lock(SyncLock) + { + return Random.Next(); + } + } } } \ No newline at end of file From 8c1705e645cd867222c73a48c5986b27f9344802 Mon Sep 17 00:00:00 2001 From: Aleksandr Piskunov Date: Sun, 12 Mar 2023 20:22:28 +0300 Subject: [PATCH 4/5] Delete redundant attributes. Add TypeExtensions to get readable generic type argument name. Add methods to build name and full name for a test. --- .../ExampleParameterisedTests.cs | 30 ++++++-- Allure.XUnit/AllureXunitHelper.cs | 45 +++++++++--- .../Attributes/AllureFullNameAttribute.cs | 22 ------ .../Attributes/AllureNameAttribute.cs | 22 ------ Allure.XUnit/TypeExtensions.cs | 73 +++++++++++++++++++ 5 files changed, 129 insertions(+), 63 deletions(-) delete mode 100644 Allure.XUnit/Attributes/AllureFullNameAttribute.cs delete mode 100644 Allure.XUnit/Attributes/AllureNameAttribute.cs create mode 100644 Allure.XUnit/TypeExtensions.cs diff --git a/Allure.XUnit.Examples/ExampleParameterisedTests.cs b/Allure.XUnit.Examples/ExampleParameterisedTests.cs index 7fbbe33e..131bfc00 100644 --- a/Allure.XUnit.Examples/ExampleParameterisedTests.cs +++ b/Allure.XUnit.Examples/ExampleParameterisedTests.cs @@ -1,4 +1,5 @@ using System; +using System.Diagnostics; using System.IO; using Allure.Xunit.Attributes; using Allure.XUnit.Examples.TestData; @@ -22,10 +23,10 @@ public ExampleParameterisedTests() public void TestTheoryWithMemberDataProperty(int value1, int value2, int expected) { var result = value1 + value2; - + Assert.Equal(expected, result); } - + [AllureXunitTheory] [AllureParentSuite("AllTests")] [AllureSuite("Test AllureXunitTheory")] @@ -34,10 +35,10 @@ public void TestTheoryWithMemberDataProperty(int value1, int value2, int expecte public void TestTheoryWithClassData(int value1, int value2, int expected) { var result = value1 + value2; - + Assert.Equal(expected, result); } - + [AllureXunitTheory] [AllureParentSuite("AllTests")] [AllureSuite("Test AllureXunitTheory")] @@ -61,11 +62,9 @@ public void TestTheoryWithMemberData(MyTestClass a, MyTestClass b) } [AllureXunitTheory] - [AllureName(nameof(TestTheoryWithMemberDataThatReturnsRandomData))] - [AllureFullName(nameof(TestTheoryWithMemberDataThatReturnsRandomData))] [AllureParentSuite("AllTests")] [AllureSuite("Test AllureXunitTheory")] - [AllureSubSuite("Test Test MemberData with random data")] + [AllureSubSuite("Test test MemberData with random data")] [MemberData(nameof(TestDataGenerators.RandomData), MemberType = typeof(TestDataGenerators))] public void TestTheoryWithMemberDataThatReturnsRandomData(int value1, int value2, int expected) { @@ -73,5 +72,20 @@ public void TestTheoryWithMemberDataThatReturnsRandomData(int value1, int value2 Assert.Equal(expected, result); } + + [AllureXunitTheory] + [AllureParentSuite("AllTests")] + [AllureSuite("Test AllureXunitTheory")] + [AllureSubSuite("Test test with generic arguments")] + [InlineData(5, 10)] + [InlineData(10, 20)] + public void TestTheoryWithInlineDataThatAcceptsGenericArgument(int? value, int? expected) + { + var result = value * 2; + + Debug.Assert(expected != null, nameof(expected) + " != null"); + Debug.Assert(result != null, nameof(result) + " != null"); + Assert.Equal(expected.Value, result.Value); + } } -} +} \ No newline at end of file diff --git a/Allure.XUnit/AllureXunitHelper.cs b/Allure.XUnit/AllureXunitHelper.cs index ee487bc2..64fd8336 100644 --- a/Allure.XUnit/AllureXunitHelper.cs +++ b/Allure.XUnit/AllureXunitHelper.cs @@ -5,8 +5,8 @@ using Allure.Net.Commons; using Allure.XUnit; using Allure.Xunit.Attributes; +using Xunit; using Xunit.Abstractions; -using Xunit.Sdk; namespace Allure.Xunit { @@ -49,9 +49,9 @@ public static void StartTestCase(ITestCaseMessage testCaseMessage) testResults.TestResult = new() { uuid = uuid, - name = testCase.DisplayName, + name = BuildName(testCase), historyId = testCase.DisplayName, - fullName = testCase.DisplayName, + fullName = BuildFullName(testCase), labels = new() { Label.Thread(), @@ -226,14 +226,6 @@ private static void UpdateTestDataFromAttributes(TestResult testResult, ITestCas testResult.labels.AddDistinct("story", storyAttribute.Stories, storyAttribute.Overwrite); break; - case AllureNameAttribute nameAttribute: - nameAttribute.UpdateTestResult(testResult); - break; - - case AllureFullNameAttribute fullNameAttribute: - fullNameAttribute.UpdateTestResult(testResult); - break; - case AllureDescriptionAttribute descriptionAttribute: testResult.description = descriptionAttribute.Description; break; @@ -254,5 +246,36 @@ private static void UpdateTestDataFromAttributes(TestResult testResult, ITestCas } } } + + private static string BuildName(ITestCase testCase) + { + var factAttribute = testCase.TestMethod.Method.GetCustomAttributes(typeof(FactAttribute)).SingleOrDefault(); + if (factAttribute is null) + { + return BuildFullName(testCase); + } + + var displayName = factAttribute.GetNamedArgument("DisplayName"); + if (string.IsNullOrWhiteSpace(displayName)) + { + return BuildFullName(testCase); + } + + return displayName; + } + + private static string BuildFullName(ITestCase testCase) + { + var parameters = testCase.TestMethod.Method + .GetParameters() + .Select(parameter => + $"{parameter.ParameterType.ToRuntimeType().GetFullFormattedTypeName()} {parameter.Name}") + .ToArray(); + var parametersSegment = parameters.Any() + ? $"({string.Join(", ", parameters)})" + : string.Empty; + + return $"{testCase.TestMethod.TestClass.Class.Name}.{testCase.TestMethod.Method.Name}{parametersSegment}"; + } } } \ No newline at end of file diff --git a/Allure.XUnit/Attributes/AllureFullNameAttribute.cs b/Allure.XUnit/Attributes/AllureFullNameAttribute.cs deleted file mode 100644 index 8f270ea4..00000000 --- a/Allure.XUnit/Attributes/AllureFullNameAttribute.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using Allure.Net.Commons; -using Allure.XUnit; - -namespace Allure.Xunit.Attributes -{ - [AttributeUsage(AttributeTargets.Method)] - public class AllureFullNameAttribute : Attribute, IAllureInfo - { - public AllureFullNameAttribute(string fullName) - { - FullName = fullName ?? throw new ArgumentNullException(nameof(fullName)); - } - - internal string FullName { get; } - - internal void UpdateTestResult(TestResult testResult) - { - testResult.fullName = AllureNameFormatter.Format(FullName, testResult); - } - } -} \ No newline at end of file diff --git a/Allure.XUnit/Attributes/AllureNameAttribute.cs b/Allure.XUnit/Attributes/AllureNameAttribute.cs deleted file mode 100644 index 4ebdcb8b..00000000 --- a/Allure.XUnit/Attributes/AllureNameAttribute.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using Allure.Net.Commons; -using Allure.XUnit; - -namespace Allure.Xunit.Attributes -{ - [AttributeUsage(AttributeTargets.Method)] - public class AllureNameAttribute : Attribute, IAllureInfo - { - public AllureNameAttribute(string name) - { - Name = name ?? throw new ArgumentNullException(nameof(name)); - } - - internal string Name { get; } - - internal void UpdateTestResult(TestResult testResult) - { - testResult.name = AllureNameFormatter.Format(Name, testResult); - } - } -} \ No newline at end of file diff --git a/Allure.XUnit/TypeExtensions.cs b/Allure.XUnit/TypeExtensions.cs new file mode 100644 index 00000000..4951c325 --- /dev/null +++ b/Allure.XUnit/TypeExtensions.cs @@ -0,0 +1,73 @@ +using System; +using System.Collections.Generic; +using System.Reflection; +using System.Text; + +namespace Allure.XUnit +{ + internal static class TypeExtensions + { + public static string GetFullFormattedTypeName(this Type type, Func namingRule = null) + { + namingRule ??= typeName => typeName; + if (!type.IsGenericType) + { + return namingRule.Invoke(type.Name); + } + + var nameBuilder = new StringBuilder(); + BuildGenericTypeName(type, nameBuilder, namingRule); + return nameBuilder.ToString(); + } + + private static void BuildGenericTypeName(Type type, StringBuilder nameBuilder, Func namingRule) + { + if (!type.IsGenericType) + { + return; + } + + StartGenericType(type, nameBuilder, namingRule); + for (var index = 0; index < type.GenericTypeArguments.Length; index++) + { + var genericTypeArgument = type.GenericTypeArguments[index]; + if (genericTypeArgument.IsGenericType) + { + BuildGenericTypeName(genericTypeArgument, nameBuilder, namingRule); + AppendDelimiterIfNeeded(type.GenericTypeArguments, nameBuilder, index); + continue; + } + + nameBuilder.Append(namingRule.Invoke(genericTypeArgument.Name)); + AppendDelimiterIfNeeded(type.GenericTypeArguments, nameBuilder, index); + } + + EndGenericType(nameBuilder); + } + + private static void StartGenericType( + MemberInfo type, + StringBuilder nameBuilder, + Func namingRule) + { + var typeName = namingRule.Invoke(type.Name.Substring(0, type.Name.IndexOf("`", StringComparison.Ordinal))); + nameBuilder.Append(typeName).Append('<'); + } + + private static void EndGenericType(StringBuilder nameBuilder) + { + nameBuilder.Append('>'); + } + + private static void AppendDelimiterIfNeeded( + IReadOnlyCollection genericTypeArguments, + StringBuilder nameBuilder, + int index) + { + if (genericTypeArguments.Count - index != 1) + { + nameBuilder.Append(", "); + } + } + } +} \ No newline at end of file From df71b0a947d351ce0b2431dfae1a0ae304e505cc Mon Sep 17 00:00:00 2001 From: Aleksandr Piskunov Date: Mon, 13 Mar 2023 13:13:05 +0300 Subject: [PATCH 5/5] Delete redundant file. --- Allure.XUnit/AllureNameFormatter.cs | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100644 Allure.XUnit/AllureNameFormatter.cs diff --git a/Allure.XUnit/AllureNameFormatter.cs b/Allure.XUnit/AllureNameFormatter.cs deleted file mode 100644 index b8e32d28..00000000 --- a/Allure.XUnit/AllureNameFormatter.cs +++ /dev/null @@ -1,24 +0,0 @@ -using System; -using System.Linq; -using Allure.Net.Commons; - -namespace Allure.XUnit -{ - public class AllureNameFormatter - { - private static readonly Func[] Formatters = { - (nameTemplate, testResult) => nameTemplate.Replace( - oldValue: "{params}", - newValue: string.Join(", ", testResult.parameters.Select(x => $"{x.name}"))), - - (nameTemplate, testResult) => nameTemplate.Replace( - oldValue: "{args}", - newValue: string.Join(", ", testResult.parameters.Select(x => $"{x.name}: {x.value}"))), - }; - - public static string Format(string nameTemplate, TestResult testResult) - { - return Formatters.Aggregate(nameTemplate, (current, formatter) => formatter(current, testResult)); - } - } -} \ No newline at end of file