Skip to content

Document SetUpFixture inheritance and sharing setup across projects - #1298

Merged
SeanKilleen merged 3 commits into
masterfrom
1293_setupfixture-inheritance
Oct 23, 2026
Merged

SeanKilleen merged 3 commits into
masterfrom
1293_setupfixture-inheritance

Conversation

@SeanKilleen

Copy link
Copy Markdown
Member

Closes #1293

What changed

setupfixture.md gains two sections:

  • Inheritance. [SetUpFixture] is inherited; the concrete class's namespace sets the scope; an abstract base is not a setup fixture by itself; and fixture attributes are resolved one inheritance level at a time, so [TestFixture] on the derived class wins over the inherited [SetUpFixture], while a derived class with only [Test] methods becomes a setup fixture and its tests are not discovered. Ends with the tip to put [SetUpFixture] on the concrete class anyway.
  • Sharing setup across projects. The agreed pattern from the discussions: a plain class in the shared package plus a tiny [SetUpFixture] in each consuming test project, and the static Lazy<T> alternative for when consumers cannot be asked to add a class.

onetimesetup.md and setup-and-teardown.md get a one-line cross-link each to the new sections.

Executable snippets

Every example on the page is a region in SetUpFixtureAttributeExamples.cs and runs as part of the snippets test suite. The file also contains SetUpFixtureInheritanceVerification, which builds this assembly's test tree with DefaultTestAssemblyBuilder (the same path the framework uses at discovery) and asserts:

  • the abstract base class does not appear in the tree
  • the concrete derived class is built as a SetUpFixture under its own namespace and contains the consumer tests
  • the derived class marked [TestFixture] is built as a TestFixture with one test
  • the derived class with only a [Test] method is built as a SetUpFixture and the test is absent

This confirms the third rule from the issue, which @OsirisTerje had flagged as "need to check it". The undiscovered test asserts Assert.Fail, so it would also break the suite if NUnit ever started discovering it. dotnet test --list-tests likewise does not list it. The rules match the GetFixtureBuilderAttributes loop in DefaultSuiteBuilder, which walks the inheritance chain one level at a time and stops at the first level with any fixture attribute.

Verification

  • dotnet test docs/snippets/Snippets.slnx: 608 passed, 0 failed (NUnit), 2 passed (NUnitLite)
  • markdownlint and cspell: 0 issues on the changed files
  • docfx docs/docfx.json builds; all six snippet references and the three anchor cross-links render

🤖 Generated with Claude Code

Adds an Inheritance section to the SetUpFixture page covering the attribute being inherited, the concrete class's namespace setting the scope, and derived-class attribute precedence (TestFixture wins; Test-only derived classes become setup fixtures and their tests are not discovered). Adds a Sharing setup across projects section with the plain-class-plus-per-project-SetUpFixture pattern and the static Lazy<T> alternative. All examples are executable snippets, and a verification test builds the assembly's test tree to confirm the precedence rules. Cross-links added from the OneTimeSetUp page and the setup guide.

Closes #1293

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Oct 23, 2026 •

Copy link
Copy Markdown

📖 Docs preview removed because this PR was closed.

@SeanKilleen
SeanKilleen requested review from a team and OsirisTerje and a balanced review from Copilot October 23, 2026 18:04

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

The article and published snippet incorrectly promise per-run initialization for a static Lazy<T>, which follows the loaded type's lifetime instead.

1 open issue
What changed in this PR

Addresses #1293 by documenting SetUpFixture inheritance and patterns for sharing setup logic across test projects.

Changes:

  • Explains inherited namespace scope and fixture-attribute precedence.
  • Adds shared-package and static Lazy<T> examples.
  • Adds discovery-verification tests and cross-links from related setup documentation.
File Description
docs/​snippets/​Snippets.NUnit/​Attributes/​SetUpFixtureAttributeExamples.cs Adds inheritance and sharing examples, plus discovery-verification tests.
docs/​articles/​nunit/​writing-tests/​setup-and-teardown.md Links to the inheritance and shared-setup guidance.
docs/​articles/​nunit/​writing-tests/​attributes/​setupfixture.md Documents inheritance rules and cross-project setup patterns.
docs/​articles/​nunit/​writing-tests/​attributes/​onetimesetup.md Links to the shared-package setup pattern.

Review effort: Balanced

[!code-csharp[SetUpFixtureSharingConsumer](~/snippets/Snippets.NUnit/Attributes/SetUpFixtureAttributeExamples.cs#SetUpFixtureSharingConsumer)]

If you cannot ask consumers to add a class, start the resource on first use from a static `Lazy<T>` in the base test
class. It starts once per test run, but NUnit offers no hook to stop it at the end of the run, so use this only for

@OsirisTerje OsirisTerje left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very good to have this described. We talk about typical patterns for usage. This is one of them. Hope we can reach more of these.

Comment thread docs/articles/nunit/writing-tests/attributes/setupfixture.md Outdated
SeanKilleen and others added 2 commits October 23, 2026 14:40
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Addresses Copilot review feedback on PR #1298.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
@SeanKilleen
SeanKilleen merged commit 7f62c2b into master Oct 23, 2026
6 checks passed
@SeanKilleen
SeanKilleen deleted the 1293_setupfixture-inheritance branch October 23, 2026 18:47
github-actions Bot pushed a commit that referenced this pull request Oct 23, 2026
…1298)

* Document SetUpFixture inheritance and sharing setup across projects

Adds an Inheritance section to the SetUpFixture page covering the attribute being inherited, the concrete class's namespace setting the scope, and derived-class attribute precedence (TestFixture wins; Test-only derived classes become setup fixtures and their tests are not discovered). Adds a Sharing setup across projects section with the plain-class-plus-per-project-SetUpFixture pattern and the static Lazy<T> alternative. All examples are executable snippets, and a verification test builds the assembly's test tree to confirm the precedence rules. Cross-links added from the OneTimeSetUp page and the setup guide.

Closes #1293

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Say SetUpFixture can be inherited rather than is inherited

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

* Describe the static Lazy<T> lifetime as per loaded type, not per run

Addresses Copilot review feedback on PR #1298.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> 7f62c2b
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Document SetUpFixture inheritance and the shared-base-class (NuGet) pattern

3 participants