Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 33 additions & 5 deletions Allure.XUnit.Examples/ExampleParameterisedTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Diagnostics;
using System.IO;
using Allure.Xunit.Attributes;
using Allure.XUnit.Examples.TestData;
Expand All @@ -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")]
Expand All @@ -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")]
Expand All @@ -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);
}
}
}
}
20 changes: 20 additions & 0 deletions Allure.XUnit.Examples/TestData/TestDataGenerators.cs
Original file line number Diff line number Diff line change
@@ -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<object[]> Data =>
new List<object[]>
{
Expand All @@ -21,5 +26,20 @@ public class TestDataGenerators
new object[] {new MyTestClass {Test = 10}, new MyTestClass {Test = 11}}
};

public static IEnumerable<object[]> 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();
}
}
}
}
49 changes: 43 additions & 6 deletions Allure.XUnit/AllureXunitHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -49,17 +49,24 @@ 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(),
Label.Host(),
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<object>(), (param, value) => new Parameter
{
name = param.Name,
value = value?.ToString() ?? "null"
})
.ToList()
};
UpdateTestDataFromAttributes(testResults.TestResult, testCase);
AllureLifecycle.Instance.StartTestCase(testResults.TestResultContainer.uuid, testResults.TestResult);
Expand Down Expand Up @@ -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);
Expand All @@ -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<string>("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}";
}
}
}
73 changes: 73 additions & 0 deletions Allure.XUnit/TypeExtensions.cs
Original file line number Diff line number Diff line change
@@ -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<string, string> 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<string, string> 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<string, string> 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<Type> genericTypeArguments,
StringBuilder nameBuilder,
int index)
{
if (genericTypeArguments.Count - index != 1)
{
nameBuilder.Append(", ");
}
}
}
}