Skip to content

Commit e92c460

Browse files
committed
New Attributes documentation
1 parent be5276c commit e92c460

12 files changed

Lines changed: 883 additions & 3 deletions
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
---
2+
uid: netplatformattribute
3+
---
4+
5+
# NetPlatform
6+
7+
The `NetPlatformAttribute` is used to specify platforms for which a test or fixture should be run. It is a modern
8+
replacement for the [Platform](platform.md) attribute, using platform names based on the .NET `TargetFramework`
9+
conventions as documented in [CA1416: Validate platform
10+
compatibility](https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1416).
11+
12+
Platforms are specified using case-insensitive string values and may be either included or excluded from the run by use
13+
of the `Include` or `Exclude` properties respectively. Multiple comma-separated values may be specified.
14+
15+
If a test or fixture with the `NetPlatformAttribute` does not satisfy the specified platform requirements, it is
16+
skipped.
17+
18+
> [!NOTE]
19+
> This attribute was introduced in NUnit 4.6 and provides better alignment with .NET's built-in platform checking
20+
> mechanisms compared to the older `PlatformAttribute`.
21+
22+
## Test Fixture Syntax
23+
24+
[!code-csharp[NetPlatformFixture](~/snippets/Snippets.NUnit/Attributes/NetPlatformAttributeExamples.cs#NetPlatformFixture)]
25+
26+
## Test Syntax
27+
28+
[!code-csharp[NetPlatformBasic](~/snippets/Snippets.NUnit/Attributes/NetPlatformAttributeExamples.cs#NetPlatformBasic)]
29+
30+
## Excluding Platforms
31+
32+
[!code-csharp[NetPlatformExclude](~/snippets/Snippets.NUnit/Attributes/NetPlatformAttributeExamples.cs#NetPlatformExclude)]
33+
34+
## Platform Version Requirements
35+
36+
You can specify minimum version requirements for platforms:
37+
38+
[!code-csharp[NetPlatformVersion](~/snippets/Snippets.NUnit/Attributes/NetPlatformAttributeExamples.cs#NetPlatformVersion)]
39+
40+
## Multiple Platforms
41+
42+
[!code-csharp[NetPlatformMultiple](~/snippets/Snippets.NUnit/Attributes/NetPlatformAttributeExamples.cs#NetPlatformMultiple)]
43+
44+
## Platform Specifiers
45+
46+
The following platform names are supported, matching the .NET SDK's supported platform identifiers:
47+
48+
| Platform | Description |
49+
| ---------- | ------------- |
50+
| `windows` | Microsoft Windows |
51+
| `linux` | Linux distributions |
52+
| `macos` | Apple macOS |
53+
| `android` | Android |
54+
| `ios` | Apple iOS |
55+
| `tvos` | Apple tvOS |
56+
| `watchos` | Apple watchOS |
57+
| `browser` | WebAssembly in browser |
58+
59+
### Version Specifiers
60+
61+
Platform names can include version numbers to specify minimum version requirements:
62+
63+
* `windows10.0` - Windows 10 or later
64+
* `windows10.0.19041` - Windows 10 build 19041 or later
65+
* `macos10.15` - macOS Catalina (10.15) or later
66+
* `ios14.0` - iOS 14 or later
67+
68+
> [!NOTE]
69+
> For Windows, public version numbers (like Windows 7, 8, 10, 11) are automatically mapped to their internal version
70+
> numbers for compatibility checking.
71+
72+
## Comparison with PlatformAttribute
73+
74+
| Feature | NetPlatformAttribute | PlatformAttribute |
75+
| --------- | --------------------- | ------------------- |
76+
| Platform names | .NET SDK style (`windows`, `linux`, `macos`) | Legacy style (`Win`, `Unix`, `MacOsX`) |
77+
| Version support | Full version specifiers (`windows10.0.19041`) | Limited version support |
78+
| Runtime detection | Uses `OperatingSystem.IsOSPlatform()` | Uses custom detection logic |
79+
| Analyzer support | Compatible with CA1416 | Not compatible |
80+
81+
## See Also
82+
83+
* [Platform Attribute](platform.md)
84+
* [Culture Attribute](culture.md)
85+
* [CA1416: Validate platform compatibility](https://learn.microsoft.com/en-us/dotnet/fundamentals/code-analysis/quality-rules/ca1416)
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
---
2+
uid: notestsattribute
3+
---
4+
5+
# NoTests
6+
7+
The `NoTestsAttribute` specifies the default status for a parameterized test method or test fixture when it contains no
8+
executable child tests. This is useful when test cases are generated dynamically and may sometimes produce an empty
9+
set.
10+
11+
By default, NUnit treats a `Theory` with no test cases as a failure. For other parameterized tests, the behavior may
12+
vary. The `NoTestsAttribute` allows you to explicitly control what status should be reported when no test cases are
13+
available.
14+
15+
> [!NOTE]
16+
> This attribute was introduced in NUnit 4.6.
17+
18+
## Usage
19+
20+
The attribute accepts a `TestStatus` value that determines how the test should be reported when no child tests exist:
21+
22+
* `TestStatus.Skipped` - The test is marked as skipped
23+
* `TestStatus.Inconclusive` - The test is marked as inconclusive
24+
* `TestStatus.Passed` - The test is marked as passed (use with caution)
25+
* `TestStatus.Failed` - The test is marked as failed (default for Theory)
26+
27+
## Test Fixture Syntax
28+
29+
Apply to a fixture to affect all parameterized tests within it:
30+
31+
[!code-csharp[NoTestsSkipped](~/snippets/Snippets.NUnit/Attributes/NoTestsAttributeExamples.cs#NoTestsSkipped)]
32+
33+
## Test Method Syntax
34+
35+
Apply directly to a test method:
36+
37+
[!code-csharp[NoTestsOnMethod](~/snippets/Snippets.NUnit/Attributes/NoTestsAttributeExamples.cs#NoTestsOnMethod)]
38+
39+
## Inconclusive Status
40+
41+
Use `TestStatus.Inconclusive` when empty test cases indicate an indeterminate state rather than a skip:
42+
43+
[!code-csharp[NoTestsInconclusive](~/snippets/Snippets.NUnit/Attributes/NoTestsAttributeExamples.cs#NoTestsInconclusive)]
44+
45+
## Common Scenarios
46+
47+
### Dynamic Test Data
48+
49+
When test cases come from external sources (databases, APIs, configuration files) that might be empty:
50+
51+
```csharp
52+
[TestFixture]
53+
[NoTests(TestStatus.Skipped)]
54+
public class DataDrivenTests
55+
{
56+
[TestCaseSource(typeof(ExternalDataSource))]
57+
public void ProcessData(DataRecord record)
58+
{
59+
// Test implementation
60+
}
61+
}
62+
```
63+
64+
### Conditional Test Execution
65+
66+
When test cases are only available under certain conditions:
67+
68+
```csharp
69+
[NoTests(TestStatus.Inconclusive)]
70+
[TestCaseSource(nameof(GetPlatformSpecificCases))]
71+
public void PlatformSpecificTest(string testCase)
72+
{
73+
// Test only runs when platform-specific cases are available
74+
}
75+
```
76+
77+
### Feature Flag Testing
78+
79+
When tests depend on feature flags that may not be enabled:
80+
81+
```csharp
82+
[TestFixture]
83+
[NoTests(TestStatus.Skipped)]
84+
public class FeatureFlagTests
85+
{
86+
[TestCaseSource(nameof(GetEnabledFeatures))]
87+
public void TestFeature(string featureName)
88+
{
89+
// Tests features that are currently enabled
90+
}
91+
}
92+
```
93+
94+
## Inheritance
95+
96+
The `NoTestsAttribute` can be applied at the assembly, class, or method level:
97+
98+
* **Assembly level**: Affects all parameterized tests in the assembly
99+
* **Class level**: Affects all parameterized tests in the fixture
100+
* **Method level**: Affects only the specific test method
101+
102+
When multiple levels specify the attribute, the most specific level (method) takes precedence.
103+
104+
## See Also
105+
106+
* [TestCaseSource Attribute](testcasesource.md)
107+
* [TestCase Attribute](testcase.md)
108+
* [Theory Attribute](theory.md)
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
---
2+
uid: testassemblydirectoryresolveattribute
3+
---
4+
5+
# TestAssemblyDirectoryResolve
6+
7+
The `TestAssemblyDirectoryResolveAttribute` marks a test assembly as needing a special assembly resolution hook. When
8+
applied, NUnit will explicitly search the test assembly's directory for dependent assemblies during resolution.
9+
10+
This attribute is designed to work around a specific conflict between mixed-mode assembly initialization and tests
11+
running in their own AppDomain.
12+
13+
> [!NOTE]
14+
> This attribute has been available since NUnit 3.2 and addresses edge cases in assembly loading scenarios.
15+
16+
## When to Use
17+
18+
This attribute is typically needed when:
19+
20+
* Your test assembly references mixed-mode assemblies (assemblies containing both managed and native code)
21+
* Tests run in a separate AppDomain from the main process
22+
* Assembly resolution fails because dependent assemblies cannot be found
23+
24+
## Usage
25+
26+
Apply the attribute at the assembly level in your test project:
27+
28+
```csharp
29+
[assembly: TestAssemblyDirectoryResolve]
30+
```
31+
32+
This is typically placed in a file like `AssemblyInfo.cs` or a dedicated assembly attributes file.
33+
34+
## Example
35+
36+
### AssemblyInfo.cs
37+
38+
```csharp
39+
using NUnit.Framework;
40+
41+
[assembly: TestAssemblyDirectoryResolve]
42+
```
43+
44+
### Or in a dedicated file (AssemblyAttributes.cs)
45+
46+
```csharp
47+
using NUnit.Framework;
48+
49+
// Enable explicit assembly directory resolution for this test assembly
50+
[assembly: TestAssemblyDirectoryResolve]
51+
```
52+
53+
## How It Works
54+
55+
When this attribute is present on a test assembly:
56+
57+
1. NUnit registers an assembly resolution handler before running tests
58+
2. When the runtime cannot find an assembly, the handler searches the test assembly's directory
59+
3. If the assembly is found, it is loaded from that location
60+
4. This resolves issues where the default probing paths don't include the test assembly's directory
61+
62+
## Common Scenarios
63+
64+
### Mixed-Mode Assembly Dependencies
65+
66+
```csharp
67+
// AssemblyInfo.cs
68+
using NUnit.Framework;
69+
70+
// Required because we reference a mixed-mode native interop library
71+
[assembly: TestAssemblyDirectoryResolve]
72+
```
73+
74+
### Plugin or Extension Testing
75+
76+
When testing plugin systems where assemblies are loaded from non-standard locations:
77+
78+
```csharp
79+
[assembly: TestAssemblyDirectoryResolve]
80+
81+
// Tests can now properly resolve plugin dependencies
82+
[TestFixture]
83+
public class PluginTests
84+
{
85+
[Test]
86+
public void PluginLoadsSuccessfully()
87+
{
88+
var plugin = LoadPlugin("MyPlugin.dll");
89+
Assert.That(plugin, Is.Not.Null);
90+
}
91+
}
92+
```
93+
94+
## Verification
95+
96+
[!code-csharp[VerifyAttributeExists](~/snippets/Snippets.NUnit/Attributes/TestAssemblyDirectoryResolveAttributeExamples.cs#VerifyAttributeExists)]
97+
98+
## Limitations
99+
100+
* This attribute only affects assembly resolution within the test assembly's AppDomain
101+
* It does not affect assemblies loaded in child AppDomains or separate processes
102+
* The attribute has no effect if the test assembly directory is already in the probing path
103+
104+
## See Also
105+
106+
* [NonTestAssembly Attribute](nontestassembly.md)
107+
* [.NET Assembly Loading](https://learn.microsoft.com/en-us/dotnet/framework/deployment/how-the-runtime-locates-assemblies)

docs/articles/nunit/writing-tests/attributes/testcase.md

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,3 +87,58 @@ CLR.
8787

8888
As a result, when **TestCaseAttribute** appears multiple times on a method or when other data-providing attributes are
8989
used in combination with **TestCaseAttribute**, the order of the test cases is undefined.
90+
91+
## Generic TestCase Attributes
92+
93+
NUnit provides generic versions of `TestCaseAttribute` that offer compile-time type safety for test arguments. These are
94+
available as `TestCaseAttribute<T>` through `TestCaseAttribute<T1, T2, T3, T4, T5>`, supporting up to 5 type parameters.
95+
96+
> [!NOTE]
97+
> From NUnit 4.6
98+
> Generic TestCase attributes are only available on .NET 6.0 and later. They are not supported on .NET Framework.
99+
100+
### Single Type Parameter
101+
102+
[!code-csharp[GenericTestCaseSingleType](~/snippets/Snippets.NUnit/Attributes/TestCaseGenericExamples.cs#GenericTestCaseSingleType)]
103+
104+
### Multiple Type Parameters
105+
106+
[!code-csharp[GenericTestCaseTwoTypes](~/snippets/Snippets.NUnit/Attributes/TestCaseGenericExamples.cs#GenericTestCaseTwoTypes)]
107+
108+
### With Expected Result
109+
110+
Generic TestCase attributes support all the same named parameters as the regular `TestCaseAttribute`:
111+
112+
[!code-csharp[GenericTestCaseWithExpectedResult](~/snippets/Snippets.NUnit/Attributes/TestCaseGenericExamples.cs#GenericTestCaseWithExpectedResult)]
113+
114+
### Mixing Generic and Regular TestCase
115+
116+
You can mix generic and regular `TestCase` attributes on the same method:
117+
118+
[!code-csharp[GenericTestCaseMixedWithRegular](~/snippets/Snippets.NUnit/Attributes/TestCaseGenericExamples.cs#GenericTestCaseMixedWithRegular)]
119+
120+
### Benefits of Generic TestCase
121+
122+
* **Compile-time type checking**: Errors are caught at compile time rather than runtime
123+
* **Better IDE support**: IntelliSense provides accurate parameter types
124+
* **Clearer intent**: The expected types are explicit in the attribute declaration
125+
* **Refactoring safety**: Type changes are caught by the compiler
126+
127+
### Comparison with TypeArgs
128+
129+
The `TypeArgs` named parameter provides similar functionality but is specified at runtime:
130+
131+
```csharp
132+
// Using TypeArgs (runtime type specification)
133+
[TestCase(42, TypeArgs = new[] { typeof(int) })]
134+
public void TestWithTypeArgs<T>(T value) { }
135+
136+
// Using generic attribute (compile-time type specification)
137+
[TestCase<int>(42)]
138+
public void TestWithGenericAttribute<T>(T value) { }
139+
```
140+
141+
Both approaches are valid; choose based on your needs:
142+
143+
* Use **generic attributes** when you want compile-time type safety
144+
* Use **TypeArgs** when you need to specify types dynamically or when targeting .NET Framework

docs/articles/nunit/writing-tests/attributes/toc.yml

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@
4040
href: parallelizable.md
4141
- name: "[NonParallelizable]"
4242
href: nonparallelizable.md
43+
- name: "[NetPlatform]"
44+
href: netplatform.md
45+
- name: "[NoTests]"
46+
href: notests.md
4347
- name: "[Platform]"
4448
href: platform.md
4549
- name: "[Property]"
@@ -69,7 +73,9 @@
6973
- name: "[TearDown]"
7074
href: teardown.md
7175
- name: "[Test]"
72-
href: test.md
76+
href: test.md
77+
- name: "[TestAssemblyDirectoryResolve]"
78+
href: testassemblydirectoryresolve.md
7379
- name: "[TestCase]"
7480
href: testcase.md
7581
- name: "[TestCaseSource]"
@@ -87,7 +93,9 @@
8793
- name: "[Theory]"
8894
href: theory.md
8995
- name: "[Timeout]"
90-
href: timeout.md
96+
href: timeout.md
97+
- name: "[UnhandledExceptionHandling]"
98+
href: unhandledexceptionhandling.md
9199
- name: "[Values]"
92100
href: values.md
93101
- name: "[ValueSource]"

0 commit comments

Comments
 (0)