Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
80 commits
Select commit Hold shift + click to select a range
2f5ec58
feat(commons): metadata attribute API
delatrie Jan 26, 2026
035d514
feat(commons): add RunInContextAsync
delatrie Jan 26, 2026
ade6125
fix(commons): invalid member access modifier on some link attrs
delatrie Jan 26, 2026
847f832
feat(commons): add step and parameter attributes
delatrie Jan 26, 2026
1576d6f
feat(commons): simplify attributes api
delatrie Jan 27, 2026
edb193d
feat(commons): iteration 2 on metadata attributes
delatrie Jan 28, 2026
f9489a7
feat(commons): add attrs application functions
delatrie Jan 28, 2026
ed6a6a4
test(nunit): rename legacy attr tests
delatrie Jan 28, 2026
ac6f261
test(nunit): fix sample namespaces and formatting
delatrie Jan 28, 2026
93ac6a7
test(commons): move attr application tests
delatrie Jan 28, 2026
e97d56c
feat(commons): add html description attr
delatrie Jan 28, 2026
22b7907
fix(commons): rename some attribute classes
delatrie Jan 28, 2026
91cb2b5
test(commons): add allure-id, owner, and severity tests
delatrie Jan 28, 2026
b21b64b
fix(nunit): reverse nunit description application
delatrie Jan 28, 2026
2133695
test(nunit): a bunch of tests on Allure API
delatrie Jan 28, 2026
3bdb5a5
test(nunit): consolidate bdd and suite label tests
delatrie Jan 29, 2026
be91517
test(nunit): add allure id tests
delatrie Jan 29, 2026
15c8a76
test(nunit): add link tests
delatrie Jan 29, 2026
4b1e2e1
test(nunit): add issue tests
delatrie Jan 29, 2026
3252c4c
test(nunit): add tms link tests
delatrie Jan 29, 2026
526fb28
test(nunit): add display name tests
delatrie Jan 30, 2026
fcd837d
test(nunit): make nunit description tests more complete
delatrie Jan 30, 2026
e286c6f
test(nunit): add owner tests
delatrie Jan 30, 2026
c8c8bfd
feat(commons): add CreateParameters
delatrie Jan 30, 2026
e7f3731
test(commons): fix flaky concurrency tests
delatrie Jan 30, 2026
1b34baf
test(nunit): rewrite parameter tests
delatrie Jan 30, 2026
80ae2a6
docs(commons): add details to AllureParameterAttribute.Excluded
delatrie Jan 30, 2026
7337f52
test(nunit): fix step attribute tests
delatrie Jan 30, 2026
1a21dc5
test(nunit): add new step attribute tests
delatrie Jan 30, 2026
1cf7009
test(nunit): fix suite and bdd label class test name
delatrie Jan 30, 2026
fe640fe
test(nunit): add severity tests
delatrie Jan 30, 2026
7e40414
test(nunit): add tag tests
delatrie Jan 30, 2026
b5043a2
test(nunit): add meta attribute tests
delatrie Jan 30, 2026
da157e8
feat(commons): add get API for allure attrs
delatrie Jan 30, 2026
f22d710
feat(commons): support mode for step parameters
delatrie Jan 30, 2026
949188b
test(nunit): fix tests
delatrie Jan 30, 2026
ba2efd0
feat(commons): add attr ctor args as props
delatrie Jan 30, 2026
8648d7a
feat(nunit): add support for attribute API
delatrie Jan 30, 2026
d52a8e8
fix(commons): remove AttributeUsage from abstract attrs
delatrie Jan 30, 2026
d691862
feat(xunit): add support for attribute API
delatrie Jan 30, 2026
edb3da9
feat(commons): add before and after attrs
delatrie Jan 30, 2026
88bf932
feat(commons): allow fixture parameters
delatrie Jan 30, 2026
d71d9a9
test(nunit): test fixture attrs
delatrie Jan 30, 2026
480ca00
test(commons): move attr tests to api tests
delatrie Feb 2, 2026
a19a9e8
test(commons): fix potential concurrency issue
delatrie Feb 2, 2026
e66e167
feat(commons): [AllureAttachment] attribute
delatrie Feb 2, 2026
d64cdfe
feat(commons): use type formatters by [AllureAttachment]
delatrie Feb 2, 2026
5d93b2f
feat(commons): delegate byte[] content type detection to report
delatrie Feb 2, 2026
da2b051
feat(commons): avoid conversions if Allure not running
delatrie Feb 2, 2026
9a4e176
test(xunit): add bdd label tests
delatrie Feb 2, 2026
b7d6fa4
chore: run xunit tests in ci
delatrie Feb 2, 2026
567bfb5
test(xunit): add allure id tests
delatrie Feb 2, 2026
e3dbdc9
test(xunit): add custom label tests
delatrie Feb 2, 2026
0beda4c
test(xunit): add description tests
delatrie Feb 2, 2026
08ff269
test(xunit): fix some tests
delatrie Feb 2, 2026
21b7d2a
test(xunit): add link tests
delatrie Feb 2, 2026
118218c
test(xunit): add meta attribute tests
delatrie Feb 2, 2026
6485d84
test(xunit): fix some sample names
delatrie Feb 2, 2026
f889e9f
test(xunit): add display name tests
delatrie Feb 2, 2026
f982f23
test(xunit): add parameter tests
delatrie Feb 2, 2026
18952c7
fix(xunit): don't overwrite dynamic parameters
delatrie Feb 2, 2026
683d534
test(xunit): add tag tests
delatrie Feb 2, 2026
1475fa2
feat(commons): add non-reflection overload of CreateParameters
delatrie Feb 4, 2026
6471278
refactor(xunit): reuse CreateParameters
delatrie Feb 4, 2026
d1b9ec1
fix(commons): use link as the default link type when matching a template
delatrie Feb 4, 2026
5c08532
feat(commons): attachments from streams
delatrie Feb 4, 2026
d8a2631
refactor(commons): extract methods in attachment aspect
delatrie Feb 4, 2026
a138957
feat(commons): add [AllureAttachmentFile]
delatrie Feb 4, 2026
dbaaa0b
docs(commons): fix runtime API list
delatrie Feb 4, 2026
4081f77
docs(commons): document Attribute API
delatrie Feb 4, 2026
cd63216
test(commons): fix test on empty type link
delatrie Feb 5, 2026
afe232d
refactor(commons): simplify RunInContextAsync around context isolation
delatrie Feb 5, 2026
48fe25d
docs(commons): fix inaccurate attr application descriptions
delatrie Feb 5, 2026
07dd6f2
chore(xunit): fix false positive null check
delatrie Feb 5, 2026
c1889dc
docs(nunit): add attributes API info to readme
delatrie Feb 5, 2026
dd32b5a
docs(xunit): add attributes API info to readme
delatrie Feb 5, 2026
c0cea43
docs: set up fixture -> setup fixture
delatrie Feb 6, 2026
b7d9afb
feat(commons): skip class AllureName application on commons level
delatrie Feb 6, 2026
747c9b8
feat(commons): rename base attribute to AllureApiAttribute
delatrie Feb 6, 2026
a14175b
feat(commons): fix param order in attr application fns
delatrie Feb 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 4 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ jobs:
--no-restore\
--no-build\
--configuration ${{ env.BUILD_CONFIGURATION }}
dotnet run --project ./tests/Allure.Xunit.Tests\
--no-restore\
--no-build\
--configuration ${{ env.BUILD_CONFIGURATION }}
dotnet test ./tests/Allure.SpecFlow.Tests\
--no-restore\
--no-build\
Expand Down
3 changes: 3 additions & 0 deletions allure-csharp.slnx
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@
<Project Path="tests/Allure.Testing/Allure.Testing.csproj">
<Build Solution="Publish|*" Project="false" />
</Project>
<Project Path="tests/Allure.Xunit.Tests/Allure.Xunit.Tests.csproj">
<Build Solution="Publish|*" Project="false" />
</Project>
</Folder>
<Folder Name="/Solution Items/">
<File Path=".gitignore" />
Expand Down
134 changes: 85 additions & 49 deletions src/Allure.NUnit/Core/AllureNUnitHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@
using System.Linq;
using System.Text;
using Allure.Net.Commons;
using Allure.Net.Commons.Attributes;
using Allure.Net.Commons.Functions;
using Allure.Net.Commons.Sdk;
using Allure.Net.Commons.TestPlan;
using Allure.NUnit.Attributes;
using NUnit.Framework;
using NUnit.Framework.Interfaces;
using NUnit.Framework.Internal;
Expand Down Expand Up @@ -120,7 +121,8 @@ internal static TestResult CreateTestResult(ITest test)
..ModelFunctions.EnumerateGlobalLabels(),
]
};
UpdateTestDataFromAllureAttributes(test, testResult);
ApplyLegacyAllureAttributes(test, testResult);
ApplyAllureAttributes(test, testResult);
AddTestParametersFromNUnit(test, testResult);
SetIdentifiers(test, testResult);
return testResult;
Expand Down Expand Up @@ -262,40 +264,37 @@ static void SetLegacyIdentifiers(ITest test, TestResult testResult)

static void AddTestParametersFromNUnit(ITest test, TestResult testResult)
{
var arguments = CollectNUnitArguments(test);
var parameters = test.Method.MethodInfo.GetParameters();
var arguments = test.Arguments;
var formatters = AllureLifecycle.TypeFormatters;
foreach (var (name, value) in arguments)
{
testResult.parameters.Add(new()
{
name = name,
value = FormatFunctions.Format(value, formatters)
});
}

testResult.parameters.AddRange(
ModelFunctions.CreateParameters(parameters, arguments, formatters)
);
}

static IEnumerable<(string, object)> CollectNUnitArguments(ITest test) =>
test.Method.MethodInfo.GetParameters()
.Select(p => p.Name)
.Zip(
test.Arguments,
(n, v) => (n, v)
);
static void ApplyAllureAttributes(ITest test, TestResult testResult)
{
var testFixtureClass = GetTestFixture(test).TypeInfo.Type;

AllureApiAttribute.ApplyTypeAttributes(testFixtureClass, testResult);
AllureApiAttribute.ApplyMethodAttributes(test.Method.MethodInfo, testResult);
}

static void UpdateTestDataFromAllureAttributes(ITest test, TestResult testResult)
static void ApplyLegacyAllureAttributes(ITest test, TestResult testResult)
{
foreach (var attribute in IterateAllAllureAttribites(test))
{
attribute.UpdateTestResult(testResult);
}
}

static IEnumerable<AllureTestCaseAttribute> IterateAllAllureAttribites(ITest test) =>
static IEnumerable<Attributes.AllureTestCaseAttribute> IterateAllAllureAttribites(ITest test) =>
test.Method
.GetCustomAttributes<AllureTestCaseAttribute>(true)
.GetCustomAttributes<Attributes.AllureTestCaseAttribute>(true)
.Concat(
GetTestFixture(test)
.GetCustomAttributes<AllureTestCaseAttribute>(true)
.GetCustomAttributes<Attributes.AllureTestCaseAttribute>(true)
);

static string GetNamespace(string classFullName)
Expand All @@ -309,6 +308,14 @@ static string GetNamespace(string classFullName)
);
}

static string ResolveSubSuite(TestFixture testFixture)
=> AllureApiAttribute
.GetTypeAttributes(testFixture.TypeInfo.Type)
.OfType<AllureNameAttribute>()
.LastOrDefault()
?.Name
?? GetClassName(testFixture.FullName);

static string GetClassName(string classFullName)
{
var lastDotIndex = StripTypeArgs(classFullName)?.LastIndexOf('.') ?? -1;
Expand Down Expand Up @@ -349,39 +356,66 @@ static TestFixture GetTestFixture(ITest test)

internal static void ApplyDefaultSuiteHierarchy(ITest test)
{
var testClassFullName = GetTestFixture(test).FullName;
var testFixture = GetTestFixture(test);
var testClassFullName = testFixture.FullName;
var assemblyName = test.TypeInfo?.Assembly?.GetName().Name;
var @namespace = GetNamespace(testClassFullName);
var className = GetClassName(testClassFullName);
var subSuite = ResolveSubSuite(testFixture);

AllureLifecycle.UpdateTestCase(
testResult => ModelFunctions.EnsureSuites(
testResult,
assemblyName,
@namespace,
className
subSuite
)
);
}

private void UpdateTestDataFromNUnitProperties()
{
foreach (var p in GetTestProperties(PropertyNames.Description))
this.ApplyNUnitDescriptions();
this.ApplyNUnitAuthors();
this.ApplyNUnitCategories();
}

void ApplyNUnitDescriptions()
{
bool hasDescription = false;
AllureLifecycle.UpdateTestCase((tr) =>
{
AllureLifecycle.UpdateTestCase(x => x.description += $"{p}\n"
);
hasDescription = tr.description is not null || tr.descriptionHtml is not null;
});

if (hasDescription)
{
// If a description is provided via the Allure API,
// NUnit descriptions are ignored.
return;
}

foreach (var p in GetTestProperties(PropertyNames.Author))
foreach (var p in EnumerateTestProperties(PropertyNames.Description))
{
AllureLifecycle.UpdateTestCase(x => x.labels.Add(Label.Owner(p))
);
AllureLifecycle.UpdateTestCase(x =>
x.description = string.IsNullOrEmpty(x.description)
? p
: $"{x.description}\n\n{p}");
}
}

foreach (var p in GetTestProperties(PropertyNames.Category))
void ApplyNUnitAuthors()
{
foreach (var p in EnumerateTestProperties(PropertyNames.Author))
{
AllureLifecycle.UpdateTestCase(x => x.labels.Add(Label.Tag(p))
);
AllureLifecycle.UpdateTestCase(x => x.labels.Add(Label.Owner(p)));
}
}

void ApplyNUnitCategories()
{
foreach (var p in EnumerateTestProperties(PropertyNames.Category))
{
AllureLifecycle.UpdateTestCase(x => x.labels.Add(Label.Tag(p)));
}
}

Expand All @@ -402,30 +436,32 @@ private void AddConsoleOutputAttachment()
}
}

private IEnumerable<string> GetTestProperties(string name)
IEnumerable<string> EnumerateTestProperties(string name)
{
var list = new List<string>();
var currentTest = _test;
while (currentTest.GetType() != typeof(TestSuite)
&& currentTest.GetType() != typeof(TestAssembly))
var propertyContainers = EnumeratePropertyContainers().Reverse();
foreach (var obj in propertyContainers)
{
if (currentTest.Properties.ContainsKey(name))
if (obj.Properties.ContainsKey(name))
{
if (currentTest.Properties[name].Count > 0)
for (var i = 0; i < obj.Properties[name].Count; i++)
{
for (var i = 0; i < currentTest.Properties[name].Count; i++)
{
list.Add(
currentTest.Properties[name][i].ToString()
);
}
yield return obj.Properties[name][i].ToString();
}
}
}
}

currentTest = currentTest.Parent;
IEnumerable<ITest> EnumeratePropertyContainers()
{
for (var test = this._test; ShouldContinue(test); test = test.Parent)
{
yield return test;
}

return list;
static bool ShouldContinue(ITest test)
=> test is not null
&& test.GetType() != typeof(TestSuite)
&& test.GetType() != typeof(TestAssembly);
}

private string ContainerId => $"tc-{_test.Id}";
Expand Down
150 changes: 149 additions & 1 deletion src/Allure.NUnit/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,155 @@ Some examples are available [here](https://github.com/allure-framework/allure-cs

## Notes

### Namespace changed to Allure.NUnit
### New in 2.15.0: the common Attribute API

Use the attributes in `Allure.Net.Commons.Attributes` instead of `Allure.NUnit.Attributes`. Read more details [here](https://github.com/allure-framework/allure-csharp/pull/647).

In most cases, the migration is as simple as swapping the using directive:

```diff
- using Allure.NUnit.Attributes;
+ using Allure.Net.Commons.Attributes;
using Allure.NUnit;
using NUnit.Framework;

[AllureFeature("My feature")]
class MyTestClass
{
[AllureStory("My story")]
[Test]
public void MyTestMethod()
{

}
}
```

In some cases, the usage must be updated. They are listed below.

#### `[AllureDescription]`

Set `Append` to keep the concatenation behavior:

```diff
- using Allure.NUnit.Attributes;
+ using Allure.Net.Commons.Attributes;
using NUnit.Framework;

-[AllureDescription("First description")]
+[AllureDescription("First description", Append = true)]
class MyTestClass
{
- [AllureDescription("Second description")]
+ [AllureDescription("Second description", Append = true)]
[Test]
public void MyTestMethod()
{

}
}
```

Use `[AllureDescriptionHtml]` instead of setting `Html`:

```diff
- using Allure.NUnit.Attributes;
+ using Allure.Net.Commons.Attributes;
using NUnit.Framework;

class MyTestClass
{
- [AllureDescription("<p>Html text</p>", Html = true)]
+ [AllureDescriptionHtml("<p>Html text</p>")]
[Test]
public void MyTestMethod()
{
}
}
```

#### `[AllureFeature]`, `[AllureStory]` with multiple values

Use multiple `[AllureFeature]` or `[AllureStory]` attributes instead:

```diff
- using Allure.NUnit.Attributes;
+ using Allure.Net.Commons.Attributes;

-[AllureFeature("Feature 1", "Feature 2")]
+[AllureFeature("Feature 1")]
+[AllureFeature("Feature 2")]
-[AllureStory("Story 1", "Story 2")]
+[AllureStory("Story 1")]
+[AllureStory("Story 2")]
class MyTestClass
{
}
```

#### `[AllureLink]`, `[AllureIssue]`, `[AllureTms]`

Pass the URL or ID as the only positional argument. Use the `Title` property to pass the display
text. Also, use `[AllureTmsItem]` instead of `[AllureTms]`:

```diff
- using Allure.NUnit.Attributes;
+ using Allure.Net.Commons.Attributes;

-[AllureLink("Homepage", "https://allurereport.org")]
+[AllureLink("https://allurereport.org", Title = "Homepage")]
-[AllureIssue("ISSUE-123", "123")]
+[AllureIssue("123", Title = "ISSUE-123")]
-[AllureTms("TMS-345", "345")]
+[AllureTmsItem("345", Title = "TMS-345")]
class MyTestClass
{
}
```

#### `[AllureSeverity]`

Always pass an explicit value as the argument:

```diff
- using Allure.NUnit.Attributes;
+ using Allure.Net.Commons.Attributes;

-[AllureSeverity]
+[AllureSeverity(SeverityLevel.normal)]
class MyTestClass
{
}
```

#### `[Name]` and `[Skip]`

Use `[AllureParameter]` with `Name` and `Ignore` correspondingly:

```diff
- using Allure.NUnit.Attributes;
+ using Allure.Net.Commons.Attributes;

class MyTestClass
{
[AllureStep]
public void MyStepMethod(
- [Name("Foo")] int parameter1,
+ [AllureParameter(Name = "Foo")] int parameter1,
- [Skip] int parameter2
+ [AllureParameter(Ignore = true)] int parameter2
)
{
}
}
```

#### Deprecation notice

Attributes from the `Allure.NUnit.Attributes` namespace will be deprecated in one of the future
releases. Please, migrate to `Allure.Net.Commons.Attributes`.

### New in 2.12.0: Namespace changed to Allure.NUnit

Starting from 2.12.0, the namespace `NUnit.Allure` is deprecated. The API in
that namespace still works, but it will be removed in the future. Please use
Expand Down
Loading
Loading