diff --git a/Allure.XUnit.Examples/ExampleParameterisedTests.cs b/Allure.XUnit.Examples/ExampleParameterisedTests.cs index 277f3f08..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")] @@ -59,5 +60,32 @@ public void TestTheoryWithMemberData(MyTestClass a, MyTestClass b) { Assert.Equal(a.Test, b.Test); } + + [AllureXunitTheory] + [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); + } + + [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.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 diff --git a/Allure.XUnit/AllureXunitHelper.cs b/Allure.XUnit/AllureXunitHelper.cs index 05bc3b98..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(), @@ -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); @@ -222,8 +229,7 @@ private static void UpdateTestDataFromAttributes(TestResult testResult, ITestCas 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); @@ -240,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/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