diff --git a/docs/articles/archive.md b/docs/articles/archive.md new file mode 100644 index 000000000..de537ccff --- /dev/null +++ b/docs/articles/archive.md @@ -0,0 +1,47 @@ +--- +uid: archive +--- + +# Archive + +These pages describe older versions of NUnit, features that were removed or deprecated, and tools that are no longer +maintained. They are kept for reference, and for anyone still working with older versions. + +For the current version, start at the [documentation home page](../index.md). + +## Older versions of NUnit + +* [NUnit 2.x documentation](xref:legacydocs) +* [Release notes before NUnit 3.5](xref:pre35releasenotes) +* [Breaking changes up to NUnit 4.0](xref:breakingchanges) +* [Migrating to NUnit 4](xref:migrationguidance) +* [Upgrading from NUnit 2 and 3](nunit/getting-started/upgrading.md) +* [Towards NUnit 4](xref:towardsnunit4) +* [.NET Core and .NET Standard](nunit/getting-started/dotnet-core-and-dotnet-standard.md) + +## Deprecated and removed features + +* [AssertionHelper](nunit/writing-tests/AssertionHelper.md), deprecated in NUnit 3.7 +* [ListMapper](nunit/writing-tests/ListMapper.md), removed in NUnit 4.0 +* [Addin Replacement in the Framework](xref:addinreplacementintheframework), the move away from NUnit 2 add-ins +* [Visual Studio Support](xref:visualstudiosupport), for Visual Studio 2003 and 2005 and the NUnit 2 GUI + +## Tools that are no longer maintained + +* [NUnit Xamarin Runners](xref:xamarinrunners) +* [NUnit VS Test Generator](xref:vstestgenerator) +* [NUnit Project Editor](https://github.com/nunit-legacy/nunit-project-editor/wiki/Project-Editor) + +## Older release notes + +* [Test Adapter V3 release notes](vs-test-adapter/AdapterV3-Release-Notes.md) +* [Test Adapter V2 release notes](vs-test-adapter/AdapterV2-Release-Notes.md) +* [Test Generator release notes for Visual Studio 2017 and 2019](vs-test-generator/TestGenerator-Release-Notes-VS2017-VS2019.md) +* [Test Generator release notes for Visual Studio 2015](vs-test-generator/TestGenerator-Release-Notes-VS2015.md) + +## Developer history + +* [Notes Toward NUnit 4.0](developer-info/Notes-Toward-NUnit-4.0.md) +* [NUnit 3.0 Architecture (2009)](xref:nunit3architecture2009) +* [Packaging the V2 Adapter](developer-info/Packaging-the-V2-Adapter.md) +* [Packaging the Installer](developer-info/Packaging-the-Installer.md), for the MSI installer that is no longer produced diff --git a/docs/articles/developer-info/Packaging.md b/docs/articles/developer-info/Packaging.md new file mode 100644 index 000000000..99c73977f --- /dev/null +++ b/docs/articles/developer-info/Packaging.md @@ -0,0 +1,14 @@ +--- +uid: packaging +--- + +# Packaging + +These pages describe how the NUnit team packages and releases each component. + +* [Packaging the Framework](Packaging-the-Framework.md) +* [Packaging the Console and Engine](Packaging-the-Console-and-Engine.md) +* [Packaging the V3/V4 Adapter](Packaging-the-V3-and-V4-Adapter.md) +* [Packaging Extensions](Packaging-Extensions.md) + +Instructions for packaging the V2 adapter and the MSI installer are in the [Archive](xref:archive). diff --git a/docs/articles/developer-info/toc.yml b/docs/articles/developer-info/toc.yml index 2f6f42703..f578cc680 100644 --- a/docs/articles/developer-info/toc.yml +++ b/docs/articles/developer-info/toc.yml @@ -4,8 +4,6 @@ href: Team-Practices.md - name: Specifications topicUid: specifications -- name: Notes Toward NUnit 4.0 - href: Notes-Toward-NUnit-4.0.md - name: Best Practices for XML Documentation href: Best-practices-for-XML-documentation.md - name: Coding Standards @@ -14,15 +12,13 @@ href: Contributions.md - name: Issue Tracking href: Issue-Tracking.md +- name: Packaging + href: Packaging.md - name: Packaging Extensions href: Packaging-Extensions.md - name: Packaging the Console and Engine href: Packaging-the-Console-and-Engine.md - name: Packaging the Framework href: Packaging-the-Framework.md -- name: Packaging the Installer - href: Packaging-the-Installer.md -- name: Packaging the V2 Adapter - href: Packaging-the-V2-Adapter.md - name: Packaging the V3/V4 Adapter href: Packaging-the-V3-and-V4-Adapter.md diff --git a/docs/articles/nunit-engine/Index.md b/docs/articles/nunit-engine/Index.md index bfba78136..13b625bc4 100644 --- a/docs/articles/nunit-engine/Index.md +++ b/docs/articles/nunit-engine/Index.md @@ -13,6 +13,7 @@ engine and run tests as required. > rather than using one of the many existing test runners in the ecosystem. If you are looking to simply run tests that > you have written, see the [running tests](xref:runningtests) section. -The engine exposes [an API](xref:testengineapi) designed to be used by test runners, which will be maintained in a +To start using the engine in your own runner, see [Getting Started](xref:gettingstartedengine). The engine exposes +[an API](xref:testengineapi) designed to be used by test runners, which will be maintained in a backwards-compatible fashion wherever possible. The engine also hosts various extension points, to allow further customization. diff --git a/docs/articles/nunit-engine/github-release-notes.md b/docs/articles/nunit-engine/github-release-notes.md new file mode 100644 index 000000000..9f5302dbf --- /dev/null +++ b/docs/articles/nunit-engine/github-release-notes.md @@ -0,0 +1,14 @@ +--- +uid: consoleenginegithubreleasenotes +--- + +# Console and Engine Release Notes + +From version 3.18.0, the release notes for the NUnit Console and Engine are published with each release on GitHub: + +**[NUnit Console and Engine releases on GitHub](https://github.com/nunit/nunit-console/releases)** + +Each release there lists the issues that were fixed and links to the downloads, including the NUnit Console and +Engine 4.0 pre-releases. + +For version 3.17.0 and earlier, see the [release notes up to 3.17](xref:consoleenginereleasenotes). diff --git a/docs/articles/nunit-engine/release-notes.md b/docs/articles/nunit-engine/release-notes.md index 0bbc806e9..16d96cd7c 100644 --- a/docs/articles/nunit-engine/release-notes.md +++ b/docs/articles/nunit-engine/release-notes.md @@ -6,6 +6,10 @@ uid: consoleenginereleasenotes # Console and Engine Release Notes +> [!NOTE] +> This page covers version 3.17.0 and earlier. The release notes for later versions are published on GitHub, see +> [Console and Engine Release Notes](xref:consoleenginegithubreleasenotes). + ## NUnit Console & Engine 3.17.0 - January 4, 2024 This release adds support for .net 8 by adding a missing agent. diff --git a/docs/articles/nunit-engine/toc.yml b/docs/articles/nunit-engine/toc.yml index 98d7a3938..9a40f64f6 100644 --- a/docs/articles/nunit-engine/toc.yml +++ b/docs/articles/nunit-engine/toc.yml @@ -7,5 +7,5 @@ - name: Engine Extensions href: extensions/toc.yml topicHref: extensions/Index.md -- name: Release Notes - href: release-notes.md +- name: Release Notes + href: github-release-notes.md diff --git a/docs/articles/nunit/getting-started/toc.yml b/docs/articles/nunit/getting-started/toc.yml index 8836c4b41..0f3e9d0e6 100644 --- a/docs/articles/nunit/getting-started/toc.yml +++ b/docs/articles/nunit/getting-started/toc.yml @@ -2,11 +2,6 @@ href: installation.md - name: Downloading href: downloading.md -- name: Upgrading - href: upgrading.md - name: Samples href: samples.md -- name: Breaking Changes - topicUid: breakingchanges -- name: .NET Core and .NET Standard - href: dotnet-core-and-dotnet-standard.md + diff --git a/docs/articles/nunit/intro.md b/docs/articles/nunit/intro.md index fbb52ed31..439805bd6 100644 --- a/docs/articles/nunit/intro.md +++ b/docs/articles/nunit/intro.md @@ -4,11 +4,27 @@ uid: intro # NUnit Documentation -This documentation covers NUnit 3.0 and higher. +NUnit is the open-source unit-testing framework for all .NET languages. This section documents the NUnit framework, +NUnitLite and the NUnit Console, from NUnit 3 up to the current version, NUnit 5. -Where applicable, we have marked sections with the version in which a feature first appeared. +Most of the content applies to all these versions. Where a feature was added or changed in a specific version, the +page says so, for example "This constraint was added in NUnit 4.2". Behavior from earlier versions is described in +notes or in sections such as *NUnit 4 and earlier*. -If you are new to NUnit, we suggest you begin by reading the Getting Started section of this site. Those who have used -earlier releases may want to begin with the Upgrading section. +## Where to start -See the [Release Notes](xref:frameworkreleasenotes) for more information on each release. +* **New to NUnit?** Start with [Installation](xref:installation) to create a test project, and then + [Ordinary Tests](xref:ordinarytests) to write your first test. +* **Moving to NUnit 5?** See [What's new in NUnit 5](xref:v5newfeatures) and + [the breaking changes in NUnit 5](xref:v5breakingchanges). +* **Looking for a specific attribute, assertion or constraint?** See [Attributes](writing-tests/attributes.md), + [Assertions](xref:assertions) and [Constraints](xref:constraints). +* **What changed in a release?** See the [release notes](xref:frameworkreleasenotes). + +The [documentation home page](../../index.md) gives an overview of everything, including the test adapter, the +analyzers and the NUnit engine. + +## NUnit 2 + +NUnit 2 is a different product, with its own design and its own documentation. It is not covered here. Its +documentation is kept in the [Archive](xref:legacydocs). diff --git a/docs/articles/nunit/license.md b/docs/articles/nunit/license.md index f6f03d4a6..00cc7007e 100644 --- a/docs/articles/nunit/license.md +++ b/docs/articles/nunit/license.md @@ -1,6 +1,9 @@ # NUnit License -## Copyright (c) 2004-2021 Charlie Poole, Rob Prouse and Contributors. +> [!NOTE] +> This is the former license. Now replaced with an [MIT license](https://github.com/nunit/docs/blob/master/LICENSE.md). + +## Copyright (c) 2004-2021 Charlie Poole, Rob Prouse and Contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/docs/articles/nunit/release-notes/toc.yml b/docs/articles/nunit/release-notes/toc.yml index b5f1190ef..3cd8a39b7 100644 --- a/docs/articles/nunit/release-notes/toc.yml +++ b/docs/articles/nunit/release-notes/toc.yml @@ -1,10 +1,4 @@ - name: Framework href: framework.md - name: Console and Engine - topicUid: consoleenginereleasenotes -- name: Migration Guidance - topicUid: migrationguidance -- name: Breaking Changes - topicUid: breakingchanges -- name: Pre-3.5 Release notes - href: Pre-3.5-Release-Notes.md \ No newline at end of file + topicUid: consoleenginegithubreleasenotes diff --git a/docs/articles/nunit/running-tests/Console-Runner.md b/docs/articles/nunit/running-tests/Console-Runner.md index aa8bc5bf8..e93169475 100644 --- a/docs/articles/nunit/running-tests/Console-Runner.md +++ b/docs/articles/nunit/running-tests/Console-Runner.md @@ -3,6 +3,8 @@ The nunit3-console.exe program is a text-based runner for listing and running our tests from the command-line. It is able to run all NUnit 3.0 or higher tests natively and can run NUnit 2.x tests if the v2 driver is installed. +All the options are described in [Console Command Line](xref:consolecommandline). + This runner is useful for automation of tests and integration into other systems. It automatically saves its results in XML format, allowing you to produce reports or otherwise process the results. The following is a screenshot of the console program output. diff --git a/docs/articles/nunit/running-tests/NUnitLite-Runner.md b/docs/articles/nunit/running-tests/NUnitLite-Runner.md index 28b5f76b6..45c56536d 100644 --- a/docs/articles/nunit/running-tests/NUnitLite-Runner.md +++ b/docs/articles/nunit/running-tests/NUnitLite-Runner.md @@ -52,6 +52,8 @@ dotnet run If you install the NUnitLite runner via the NuGet package, steps 2 is handled automatically. Both assemblies are installed and referenced for you. +All the options are described in [NUnitLite Options](NUnitLite-Options.md). + ## NUnitLite Output As seen in the following screen shot, the output from an NUnitLite run is quite similar to that from the console runner. diff --git a/docs/articles/nunit/technical-notes/nunit-internals/toc.yml b/docs/articles/nunit/technical-notes/nunit-internals/toc.yml index 0a3255cf4..1750a1284 100644 --- a/docs/articles/nunit/technical-notes/nunit-internals/toc.yml +++ b/docs/articles/nunit/technical-notes/nunit-internals/toc.yml @@ -19,8 +19,6 @@ href: Attribute-Hierarchy.md - name: Test Discovery And Execution href: Test-Discovery-And-Execution.md -- name: NUnit 3.0 Architecture (2009) - href: NUnit-3.0-Architecture-(2009).md - name: Specifications href: specs/toc.yml topicHref: specs/Specifications.md \ No newline at end of file diff --git a/docs/articles/nunit/technical-notes/usage/Trace-and-Debug-Output.md b/docs/articles/nunit/technical-notes/usage/Trace-and-Debug-Output.md index 2a5138e50..a4f6ca61f 100644 --- a/docs/articles/nunit/technical-notes/usage/Trace-and-Debug-Output.md +++ b/docs/articles/nunit/technical-notes/usage/Trace-and-Debug-Output.md @@ -100,6 +100,9 @@ test fixture/class. If you like you can change that to another kind of listener. +For how the test adapter shows this output in Visual Studio and `dotnet test`, see +[Trace and Debug Output in the adapter](../../../vs-test-adapter/Trace-and-Debug.md). + ## Discussion and source This issue has been discussed at [Issue 718](https://github.com/nunit/nunit3-vs-adapter/issues/718) and diff --git a/docs/articles/nunit/technical-notes/usage/Usage-Notes.md b/docs/articles/nunit/technical-notes/usage/Usage-Notes.md index 1e38e050f..b3f65d4e9 100644 --- a/docs/articles/nunit/technical-notes/usage/Usage-Notes.md +++ b/docs/articles/nunit/technical-notes/usage/Usage-Notes.md @@ -5,10 +5,9 @@ * [Assembly Isolation](Assembly-Isolation.md) * [Configuration Files](Configuration-Files.md) * [XML Formats](XML-Formats.md) -* [Visual Studio Support](Visual-Studio-Support.md) +* [NUnit Test Projects](xref:nunittestprojects) * [SetUp and TearDown](SetUp-and-TearDown.md) * [Parameterized Tests](Parameterized-Tests.md) -* [Addin Replacement in the Framework](Addin-Replacement-in-the-Framework.md) * [Counting Tests](Counting-Tests.md) * [Framework Parallel Test Execution](Framework-Parallel-Test-Execution.md) * [Engine Parallel Test Execution](Engine-Parallel-Test-Execution.md) diff --git a/docs/articles/nunit/technical-notes/usage/toc.yml b/docs/articles/nunit/technical-notes/usage/toc.yml index 0ebb37923..82fe0dd40 100644 --- a/docs/articles/nunit/technical-notes/usage/toc.yml +++ b/docs/articles/nunit/technical-notes/usage/toc.yml @@ -1,7 +1,5 @@ - name: Usage Notes href: Usage-Notes.md -- name: Addin Replacement in the Framework - href: Addin-Replacement-in-the-Framework.md - name: Assembly Isolation href: Assembly-Isolation.md - name: Configuration Files @@ -30,7 +28,5 @@ href: Test-Result-XML-Format.md - name: Trace and Debug Output href: Trace-and-Debug-Output.md -- name: Visual Studio Support - href: Visual-Studio-Support.md - name: XML Formats href: XML-Formats.md \ No newline at end of file diff --git a/docs/articles/nunit/toc.yml b/docs/articles/nunit/toc.yml index 4c4898aca..8e52dd761 100644 --- a/docs/articles/nunit/toc.yml +++ b/docs/articles/nunit/toc.yml @@ -4,10 +4,6 @@ href: V5NewFeatures.md - name: NUnit 5 Breaking Changes href: V5BreakingChanges.md -- name: NUnit 4 plans - href: Towards-NUnit4.md -- name: Migration Guidance - uid: migrationguidance - name: Release Notes href: release-notes/toc.yml topicHref: release-notes/framework.md @@ -18,7 +14,7 @@ topicHref: getting-started/installation.md - name: Writing Tests href: writing-tests/toc.yml - topicHref: writing-tests/attributes.md + topicHref: writing-tests/ordinary-tests.md - name: Running Tests href: running-tests/toc.yml topicHref: running-tests/Index.md diff --git a/docs/articles/nunit/writing-tests/automating-tests.md b/docs/articles/nunit/writing-tests/automating-tests.md new file mode 100644 index 000000000..df421f0fd --- /dev/null +++ b/docs/articles/nunit/writing-tests/automating-tests.md @@ -0,0 +1,61 @@ +--- +uid: automatingtests +--- + +# Automating Tests + +With [data driven tests](xref:datadriventests) you write out every test case yourself. NUnit can also do that work for +you: you describe the possible values for each parameter, and NUnit generates the test cases. This is a good way to +cover many inputs with very little code. + +## Every combination with [Values] + +Put [`[Values]`](xref:attribute-values) on each parameter. By default NUnit runs the test once for every combination +of the values, so the example below produces 3 × 2 = 6 test cases. + +[!code-csharp[AutomatingCombinatorial](~/snippets/Snippets.NUnit/WritingTestsGuideExamples.cs#AutomatingCombinatorial)] + +For `bool` and `enum` parameters you can leave out the values: `[Values] bool flag` gives you both `true` and +`false`. + +## A range of numbers with [Range] + +Use [`[Range]`](xref:attribute-range) to generate numbers from a start value to an end value, with an optional step. +This example runs with -10, -5, 0, 5 and 10. + +[!code-csharp[AutomatingRange](~/snippets/Snippets.NUnit/WritingTestsGuideExamples.cs#AutomatingRange)] + +## Random numbers with [Random] + +Use [`[Random]`](xref:attribute-random) to have NUnit pick values for you. This is useful for checking rules that must +hold for *any* input, such as `a + b == b + a`. NUnit records the random seed it used in the test results, so a failing run can be reproduced. + +[!code-csharp[AutomatingRandom](~/snippets/Snippets.NUnit/WritingTestsGuideExamples.cs#AutomatingRandom)] + +To create random values in the test code itself, use the [Randomizer](xref:randomizermethods) from +`TestContext.CurrentContext.Random`. It uses the same seed, so these values can be reproduced too. + +## Keeping the number of tests down + +Combinations grow fast: three parameters with ten values each give a thousand test cases. NUnit has two attributes that +change how the values are combined: + +- [`[Pairwise]`](xref:attribute-pairwise) generates just enough cases so that every *pair* of values is tested + together at least once. Most bugs are caused by one value or by two values together, so this finds most of them + with far fewer tests. +- [`[Sequential]`](xref:attribute-sequential) uses the first value of each parameter together, then the second values, + and so on, instead of all combinations. + +[!code-csharp[AutomatingPairwise](~/snippets/Snippets.NUnit/WritingTestsGuideExamples.cs#AutomatingPairwise)] + +## Theories + +A [`[Theory]`](xref:attribute-theory) goes one step further: you state something that must be true for all data +points, and NUnit tries it with every suitable value you have marked with [`[Datapoint]`](xref:attribute-datapoint) +or [`[DatapointSource]`](xref:attribute-datapointsource). + +## Next steps + +- [Combinatorial](xref:attribute-combinatorial), [Pairwise](xref:attribute-pairwise) and + [Sequential](xref:attribute-sequential) describe the combining strategies in detail. +- [Parameterized tests](xref:parameterizedtests) describes all the details of how parameterized tests work. diff --git a/docs/articles/nunit/writing-tests/data-driven-tests.md b/docs/articles/nunit/writing-tests/data-driven-tests.md new file mode 100644 index 000000000..08dbe8b31 --- /dev/null +++ b/docs/articles/nunit/writing-tests/data-driven-tests.md @@ -0,0 +1,56 @@ +--- +uid: datadriventests +--- + +# Data Driven Tests + +A data driven test runs the same test code several times, with different input data each time. Instead of copying a +test to try another value, you write the test once and give NUnit the list of values. Each set of values shows up as +its own test in the test explorer, so you can see exactly which case failed. + +NUnit calls these *parameterized tests*: the test method takes parameters, and the data is supplied from outside. + +## Inline data with [TestCase] + +Use [`[TestCase]`](xref:attribute-testcase) when you have a handful of cases that are easy to write out. Each +attribute is one test case, and its arguments are passed to the method parameters in order. + +[!code-csharp[DataDrivenTestCase](~/snippets/Snippets.NUnit/WritingTestsGuideExamples.cs#DataDrivenTestCase)] + +If the test simply computes a value, you can let the method return it and put the expected value in the attribute +with `ExpectedResult`: + +[!code-csharp[DataDrivenExpectedResult](~/snippets/Snippets.NUnit/WritingTestsGuideExamples.cs#DataDrivenExpectedResult)] + +## Data from code with [TestCaseSource] + +Use [`[TestCaseSource]`](xref:attribute-testcasesource) when the data is larger, needs code to build, or comes from +somewhere else, such as a file. Point the attribute at a static method, property or field that returns the cases. + +[!code-csharp[DataDrivenTestCaseSource](~/snippets/Snippets.NUnit/WritingTestsGuideExamples.cs#DataDrivenTestCaseSource)] + +Returning [`TestCaseData`](xref:testcasedata) objects is optional, but it lets you give each case a readable name, a +description, categories and more. To name many test cases with one pattern, see +[Template Based Test Naming](xref:templatebasedtestnaming). + +## Data for a single parameter with [ValueSource] + +Use [`[ValueSource]`](xref:attribute-valuesource) when you want to supply the values for one parameter from a +reusable list. + +[!code-csharp[DataDrivenValueSource](~/snippets/Snippets.NUnit/WritingTestsGuideExamples.cs#DataDrivenValueSource)] + +## Running a whole class with different data + +You can also pass data to the test class itself. Every test in the class then runs once for each set of arguments given +with [`[TestFixture]`](xref:attribute-testfixture). + +[!code-csharp[DataDrivenFixture](~/snippets/Snippets.NUnit/WritingTestsGuideExamples.cs#DataDrivenFixture)] + +For data built in code, use [`[TestFixtureSource]`](xref:attribute-testfixturesource) and +[`TestFixtureData`](xref:testfixturedata). + +## Next steps + +- [Automating tests](xref:automatingtests) lets NUnit generate combinations of values for you. +- [Parameterized tests](xref:parameterizedtests) describes all the details of how parameterized tests work. diff --git a/docs/articles/nunit/writing-tests/dependent-tests.md b/docs/articles/nunit/writing-tests/dependent-tests.md new file mode 100644 index 000000000..7029992f6 --- /dev/null +++ b/docs/articles/nunit/writing-tests/dependent-tests.md @@ -0,0 +1,45 @@ +--- +uid: dependenttests +--- + +# Tests That Depend on Other Tests + +Most tests should be independent: each one sets up what it needs and can run on its own, in any order. Sometimes, +though, tests really do depend on each other. An integration test may need an order to exist before it can ship it, or +a cleanup step must run after the tests that use a shared resource. + +NUnit 5 lets you say this directly with [`[DependsOnTest]`](xref:attribute-dependsontest) and +[`[DependsOnFixture]`](xref:attribute-dependsonfixture). + +> [!NOTE] +> Test dependencies were added in NUnit 5.0. + +## Depending on another test + +Put `[DependsOnTest]` on a test, with the name of the test it depends on. Use `nameof`, so the dependency still works +when the test is renamed. + +[!code-csharp[DependentTests](~/snippets/Snippets.NUnit/WritingTestsGuideExamples.cs#DependentTests)] + +- `ShipOrder` runs only after `CreateOrder` has finished. If `CreateOrder` fails, `ShipOrder` is **skipped** instead of + failing with a confusing error. +- `CleanUpOrders` sets `AllowFailure = true`, so it runs even if `ShipOrder` failed. This is the pattern for cleanup + that must always happen. + +## Depending on another fixture + +When a whole class of tests depends on another class, put [`[DependsOnFixture]`](xref:attribute-dependsonfixture) on +the class, with the type of the fixture it depends on. It works the same way: the dependent fixture waits for the other +fixture, and is skipped if that fixture fails, unless `AllowFailure` is set. + +## Things to keep in mind + +- Tests in a dependency chain can't run in parallel with each other. Don't mark them + [`[Parallelizable]`](xref:attribute-parallelizable). +- Don't combine dependencies with [`[Order]`](xref:attribute-order) in the same chain. `[DependsOnTest]` and + `[DependsOnFixture]` replace `[Order]` for most uses, and `[Order]` is deprecated. +- A circular dependency, or another invalid setup, marks the affected tests as failed, with a message that explains the + problem. + +See the [DependsOnTest](xref:attribute-dependsontest) and [DependsOnFixture](xref:attribute-dependsonfixture) reference +pages for all the details. diff --git a/docs/articles/nunit/writing-tests/flaky-and-slow-tests.md b/docs/articles/nunit/writing-tests/flaky-and-slow-tests.md new file mode 100644 index 000000000..737b7c98b --- /dev/null +++ b/docs/articles/nunit/writing-tests/flaky-and-slow-tests.md @@ -0,0 +1,63 @@ +--- +uid: flakyandslowtests +--- + +# Flaky and Slow Tests + +Some tests don't give the same result every time. They call a service that sometimes times out, test something that is +non-deterministic by nature, or now and then take far too long. NUnit has attributes for each of these cases. + +> [!TIP] +> A flaky test is often a sign of a real problem, such as a race condition or state shared between tests. Use these +> attributes to keep your build reliable while you investigate, not to hide bugs. + +## Retrying a test that sometimes fails + +[`[Retry]`](xref:attribute-retry) runs the test again when an assertion fails, up to the number of attempts you give. +The test passes as soon as one attempt passes. + +[!code-csharp[FlakyRetry](~/snippets/Snippets.NUnit/WritingTestsGuideExamples.cs#FlakyRetry)] + +The count is the total number of attempts, so `[Retry(3)]` means one run and up to two retries. By default, only +assertion failures cause a retry. List the exceptions that should also cause a retry in `RetryExceptions`. + +## Allowing some failures + +For systems that are non-deterministic by design, such as tests of AI-based features, you can accept that a test +sometimes fails. [`[Repeat]`](xref:attribute-repeat) with `RequiredPassPercentage` runs the test several times and +passes when enough of the runs pass. + +[!code-csharp[FlakyRepeatThreshold](~/snippets/Snippets.NUnit/WritingTestsGuideExamples.cs#FlakyRepeatThreshold)] + +Set `StopWhenOverallResultDetermined = true` to stop repeating as soon as the outcome is certain. `[Repeat]` without a +percentage is also a good way to *find* a flaky test: repeat it a hundred times and see whether it ever fails. + +> [!NOTE] +> `RequiredPassPercentage` and `StopWhenOverallResultDetermined` were added in NUnit 5.0. + +## Tests that take too long + +[`[MaxTime]`](xref:attribute-maxtime) fails a test that takes longer than the time you give, in milliseconds. With +`WarningTime`, a test that is slower than expected, but still within the limit, gives a warning instead. The test is +never interrupted: NUnit measures the time when it finishes. + +[!code-csharp[SlowMaxTime](~/snippets/Snippets.NUnit/WritingTestsGuideExamples.cs#SlowMaxTime)] + +## Tests that hang + +To stop a test that runs too long, use [`[CancelAfter]`](xref:attribute-cancelafter). NUnit passes a +`CancellationToken` to the test and cancels it when the time is up. The test must pass the token on to the code it +calls, so that the work actually stops. + +[!code-csharp[SlowCancelAfter](~/snippets/Snippets.NUnit/WritingTestsGuideExamples.cs#SlowCancelAfter)] + +> [!NOTE] +> The older [`[Timeout]`](xref:attribute-timeout) attribute only works on .NET Framework, and is reported as a test +> failure on .NET 5 and later. For code that can't be cancelled, `dotnet test --blame-hang-timeout` stops the whole +> test run when a test hangs. + +## See also + +- The [Retry](xref:attribute-retry), [Repeat](xref:attribute-repeat), [MaxTime](xref:attribute-maxtime) and + [CancelAfter](xref:attribute-cancelafter) reference pages +- [Warnings](Warnings.md), for how warning results are reported diff --git a/docs/articles/nunit/writing-tests/ordinary-tests.md b/docs/articles/nunit/writing-tests/ordinary-tests.md new file mode 100644 index 000000000..b2cb7993b --- /dev/null +++ b/docs/articles/nunit/writing-tests/ordinary-tests.md @@ -0,0 +1,43 @@ +--- +uid: ordinarytests +--- + +# Ordinary Tests + +Most of the tests you write will be *ordinary* tests: a method that sets something up, does one thing and checks the +result. This page shows what such a test looks like in NUnit, and where to go from there. + +## Your first test + +A test is a public method marked with the [`[Test]`](xref:attribute-test) attribute, inside a public class. The class +is called a *test fixture*. + +[!code-csharp[OrdinaryTest](~/snippets/Snippets.NUnit/WritingTestsGuideExamples.cs#OrdinaryTest)] + +The test follows the common **Arrange, Act, Assert** pattern: + +- **Arrange** creates the object you want to test, often called the *system under test*. +- **Act** calls the method you want to test. +- **Assert** checks that the result is what you expected. `Assert.That` takes the actual value and a *constraint* + that describes the expected value, such as `Is.EqualTo(5)`. + +If the assertion fails, NUnit reports the test as failed and shows both the expected and the actual value. + +## Sharing setup between tests + +When several tests need the same starting point, move the common code into a method marked with +[`[SetUp]`](xref:attribute-setup). NUnit runs it before each test in the class, so every test gets a fresh object. + +[!code-csharp[OrdinarySetUp](~/snippets/Snippets.NUnit/WritingTestsGuideExamples.cs#OrdinarySetUp)] + +Use [`[TearDown]`](xref:attribute-teardown) for cleanup after each test, and +[`[OneTimeSetUp]`](xref:attribute-onetimesetup) for expensive setup that should run only once for the whole class. +[Preparing and Cleaning Up Tests](xref:setupandteardownguide) explains all the options and when to use each one. + +## Next steps + +- [Data driven tests](xref:datadriventests) run the same test with different inputs. +- [Automating tests](xref:automatingtests) lets NUnit generate the inputs for you. +- [Multiple asserts](xref:multipleasserts) checks several things in one test and reports all the failures. +- [Constraints](xref:constraints) lists everything you can check with `Assert.That`. +- [Attributes](attributes.md) describes all the ways you can mark and control tests. diff --git a/docs/articles/nunit/writing-tests/organizing-tests.md b/docs/articles/nunit/writing-tests/organizing-tests.md new file mode 100644 index 000000000..617009f11 --- /dev/null +++ b/docs/articles/nunit/writing-tests/organizing-tests.md @@ -0,0 +1,62 @@ +--- +uid: organizingtests +--- + +# Organizing and Selecting Tests + +As a test suite grows, you often want to run only part of it: the fast tests on every build, the integration tests at +night, or the one test you are working on. NUnit lets you group tests, and then choose which groups to run. + +## Grouping tests with categories + +Put [`[Category]`](xref:attribute-category) on a test or a fixture. A test can be in several categories, and it +inherits the categories of its fixture. + +[!code-csharp[OrganizingCategories](~/snippets/Snippets.NUnit/WritingTestsGuideExamples.cs#OrganizingCategories)] + +## Running only some categories + +With `dotnet test`, filter on `TestCategory`: + +```shell +# Only the integration tests +dotnet test --filter "TestCategory=Integration" + +# Everything except the slow tests +dotnet test --filter "TestCategory!=Slow" +``` + +With the [NUnit console](xref:consolecommandline), use `--where` with the +[Test Selection Language](xref:testselectionlanguage), which can also select tests by name, class, namespace or +property: + +```shell +nunit3-console MyTests.dll --where "cat == Integration && cat != Slow" +``` + +The same expressions work with `dotnet test` through the `NUnit.Where` setting, for example +`dotnet test -- NUnit.Where="cat == Integration"`. See [Configuring with .runsettings](xref:tipsandtricks) for all the +settings. + +## Tests that run only on demand + +Mark a test with [`[Explicit]`](xref:attribute-explicit) when it should run only when you select it yourself, for +example a test that rebuilds a database. It is skipped when you run all the tests. + +## Tests that must not run for now + +Mark a test with [`[Ignore]`](xref:attribute-ignore) when it can't run at the moment, and give the reason. Ignored tests +show up as warnings, so they are not forgotten. With `Until`, the test starts running again after the given date. + +[!code-csharp[OrganizingExplicitIgnore](~/snippets/Snippets.NUnit/WritingTestsGuideExamples.cs#OrganizingExplicitIgnore)] + +> [!TIP] +> If a project contains only explicit tests, running the project runs all of them, because the adapter can't tell that +> apart from selecting them yourself. See [Explicit](xref:attribute-explicit) for details. + +## See also + +- [Test Selection Language](xref:testselectionlanguage) +- [Console Command Line](xref:consolecommandline) +- The [Category](xref:attribute-category), [Explicit](xref:attribute-explicit) and [Ignore](xref:attribute-ignore) + reference pages diff --git a/docs/articles/nunit/writing-tests/setup-and-teardown.md b/docs/articles/nunit/writing-tests/setup-and-teardown.md new file mode 100644 index 000000000..a212e134b --- /dev/null +++ b/docs/articles/nunit/writing-tests/setup-and-teardown.md @@ -0,0 +1,118 @@ +--- +uid: setupandteardownguide +--- + +# Preparing and Cleaning Up Tests + +Most tests need something prepared before they run: an object to test, a temporary folder, a database connection. Many +also need something cleaned up afterwards. NUnit lets you put this code in separate methods, marked with +`[SetUp]`, `[TearDown]`, `[OneTimeSetUp]`, `[OneTimeTearDown]` or `[SetUpFixture]`, so each test only contains +what it is actually testing. + +There are three levels, depending on how often the code should run: + +| Attribute | Runs | Use it for | +|---|---|---| +| [`[SetUp]`](xref:attribute-setup) | Before **each** test | State that every test needs a fresh copy of | +| [`[TearDown]`](xref:attribute-teardown) | After **each** test | Cleaning up what `[SetUp]` or the test created | +| [`[OneTimeSetUp]`](xref:attribute-onetimesetup) | **Once**, before all tests in the class | Expensive resources that the tests can share | +| [`[OneTimeTearDown]`](xref:attribute-onetimeteardown) | **Once**, after all tests in the class | Releasing those shared resources | +| [`[SetUpFixture]`](xref:attribute-setupfixture) | **Once** for a whole namespace, or the whole test assembly | Resources that many test classes share, such as a test server | + +## Before and after each test: [SetUp] and [TearDown] + +A method marked `[SetUp]` runs before every test in the class, and a method marked `[TearDown]` runs after every +test. This is the one to use by default: each test starts from the same, clean state, and tests can't affect each +other. + +[!code-csharp[PerTestSetUpTearDown](~/snippets/Snippets.NUnit/SetUpTearDownGuideExamples.cs#PerTestSetUpTearDown)] + +`[TearDown]` also runs when the test fails, and even when `[SetUp]` itself failed halfway. Write it so that it copes +with things that were never created, like the `Directory.Exists` check above. + +## Once for all tests in a class: [OneTimeSetUp] and [OneTimeTearDown] + +A method marked `[OneTimeSetUp]` runs once, before the first test in the class, and `[OneTimeTearDown]` runs once, +after the last one. Use them for things that are slow to create, such as loading data or starting a service, and that +the tests can safely share. + +You can combine the levels. In this example, the product catalog is expensive and only read by the tests, so it is +created once. The shopping cart is cheap and changed by every test, so each test gets a new one: + +[!code-csharp[PerFixtureOneTimeSetUp](~/snippets/Snippets.NUnit/SetUpTearDownGuideExamples.cs#PerFixtureOneTimeSetUp)] + +> [!WARNING] +> Anything created in `[OneTimeSetUp]` is shared by all tests in the class. If one test changes it, the next test sees +> the change, and the result can depend on the order the tests run in. Only share things the tests don't modify, or +> reset them in `[SetUp]`. + +## Once for many classes: [SetUpFixture] + +When several test classes need the same expensive setup, such as a test database or a web server, put it in a class +marked `[SetUpFixture]`. Its `[OneTimeSetUp]` method runs once, before any test in the **same namespace** and in its +child namespaces, and its `[OneTimeTearDown]` runs once after all of them. + +[!code-csharp[SetUpFixtureForNamespace](~/snippets/Snippets.NUnit/SetUpTearDownGuideExamples.cs#SetUpFixtureForNamespace)] + +- The namespace decides which tests the setup fixture covers. A setup fixture **outside any namespace** covers the + whole test assembly. +- The class must be public and have a default constructor, or be static. +- A setup fixture can only have `[OneTimeSetUp]` and `[OneTimeTearDown]` methods, not `[SetUp]` and `[TearDown]`. + +## Which one should I use? + +1. **Does each test need its own, fresh copy?** Use `[SetUp]` and `[TearDown]`. This is the safest choice, so start + here. +2. **Is it slow to create, and do the tests only read it?** Use `[OneTimeSetUp]` and `[OneTimeTearDown]` in the test + class. +3. **Do several test classes need it?** Use a `[SetUpFixture]` in the namespace that contains those classes, or outside + any namespace for the whole assembly. +4. **Does every test need to clean up after itself, even when it fails?** Put the cleanup in `[TearDown]` or + `[OneTimeTearDown]`, not at the end of the test, because the rest of a failing test doesn't run. + +## The order everything runs in + +For a test class in a namespace with a setup fixture, NUnit runs: + +1. `[OneTimeSetUp]` of the setup fixture outside any namespace, if there is one +2. `[OneTimeSetUp]` of the setup fixtures for the namespace, from the outermost namespace inward +3. `[OneTimeSetUp]` of the test class +4. For **each** test: `[SetUp]`, then the test, then `[TearDown]` +5. `[OneTimeTearDown]` of the test class +6. `[OneTimeTearDown]` of the setup fixtures, in the reverse order of step 1 and 2 + +With inheritance, setup methods in a base class run before those in the derived class, and teardown methods in the +derived class run before those in the base class. If a derived class overrides a base class setup method, only the +override runs, so give the methods different names instead. + +If a class has several methods with the same attribute, their order is not defined. Use one method per level, or +spread them over base and derived classes. + +## When setup fails + +- If **`[SetUp]` fails**, the test doesn't run and is reported as failed. `[TearDown]` still runs. +- If **`[OneTimeSetUp]` fails**, none of the tests in the class run, and they are all reported as failed, with the setup + error as the reason. `[OneTimeTearDown]` still runs. +- The same applies to a `[SetUpFixture]`: if its `[OneTimeSetUp]` fails, none of the tests it covers run. + +## Good to know + +- **Async setup:** all of these methods can be `async` and return a `Task`. NUnit waits for them to finish. +- **Constructors and `IDisposable`:** by default, NUnit creates one instance of the test class for all its tests, so + the constructor runs once, like `[OneTimeSetUp]`. If the class implements `IDisposable`, NUnit calls `Dispose` + when it is done with the instance. `[SetUp]` and `[TearDown]` make the intent clearer, and work the same way with + every life cycle. +- **A new instance for each test:** with + [`[FixtureLifeCycle(LifeCycle.InstancePerTestCase)]`](xref:attribute-fixturelifecycle), NUnit creates a new instance + of the test class for every test. Fields can then never leak between tests, which also helps when tests run in + [parallel](xref:attribute-parallelizable). `[OneTimeSetUp]` and `[OneTimeTearDown]` must be static in that case. +- **The current test:** inside `[SetUp]` and `[TearDown]`, [`TestContext.CurrentContext`](xref:testcontext) describes + the test that is about to run or has just run. In `[TearDown]` you can check its result, for example to save extra + logs only when a test failed. + +## See also + +- The [SetUp](xref:attribute-setup), [TearDown](xref:attribute-teardown), [OneTimeSetUp](xref:attribute-onetimesetup), + [OneTimeTearDown](xref:attribute-onetimeteardown) and [SetUpFixture](xref:attribute-setupfixture) reference pages +- [SetUp and TearDown](setup-teardown/index.md), with more details on inheritance +- [FixtureLifeCycle](xref:attribute-fixturelifecycle) diff --git a/docs/articles/nunit/writing-tests/toc.yml b/docs/articles/nunit/writing-tests/toc.yml index cfc1cf8bb..ecb896df6 100644 --- a/docs/articles/nunit/writing-tests/toc.yml +++ b/docs/articles/nunit/writing-tests/toc.yml @@ -1,3 +1,17 @@ +- name: Ordinary Tests + href: ordinary-tests.md +- name: Data Driven Tests + href: data-driven-tests.md +- name: Automating Tests + href: automating-tests.md +- name: Preparing and Cleaning Up Tests + href: setup-and-teardown.md +- name: Tests That Depend on Other Tests + href: dependent-tests.md +- name: Flaky and Slow Tests + href: flaky-and-slow-tests.md +- name: Organizing and Selecting Tests + href: organizing-tests.md - name: Attributes href: attributes.md - name: Attribute Descriptions @@ -22,10 +36,6 @@ href: TestFixtureData.md - name: TestContext href: TestContext.md -- name: AssertionHelper - href: AssertionHelper.md -- name: ListMapper - href: ListMapper.md - name: Randomizer Methods href: Randomizer-Methods.md diff --git a/docs/articles/toc.yml b/docs/articles/toc.yml index 0057a8af1..51c8368eb 100644 --- a/docs/articles/toc.yml +++ b/docs/articles/toc.yml @@ -7,12 +7,6 @@ - name: NUnit Engine href: nunit-engine/toc.yml topicHref: nunit-engine/Index.md -- name: NUnit Xamarin Runners - href: xamarin-runners/toc.yml - topicHref: xamarin-runners/index.md -- name: VS Test Generator - href: vs-test-generator/toc.yml - topicHref: vs-test-generator/Visual-Studio-Test-Generator.md - name: NUnit Analyzers href: nunit-analyzers/toc.yml topicHref: nunit-analyzers/NUnit-Analyzers.md @@ -20,9 +14,62 @@ items: - name: TestCentric GUI href: https://github.com/TestCentric/testcentric-gui/wiki - - name: NUnit Project Editor - href: https://github.com/nunit-legacy/nunit-project-editor/wiki/Project-Editor - name: Developer Info href: developer-info/toc.yml -- name: "Legacy (2.x) Docs" - href: legacy/index.md +- name: Archive + href: archive.md + items: + - name: NUnit 2.x Documentation + href: legacy/index.md + - name: Older Versions + items: + - name: Release Notes Before 3.5 + href: nunit/release-notes/Pre-3.5-Release-Notes.md + - name: Breaking Changes up to NUnit 4.0 + href: nunit/release-notes/breaking-changes.md + - name: Migrating to NUnit 4 + href: nunit/release-notes/Nunit4.0-MigrationGuide.md + - name: Upgrading from NUnit 2 and 3 + href: nunit/getting-started/upgrading.md + - name: Towards NUnit 4 + href: nunit/Towards-NUnit4.md + - name: .NET Core and .NET Standard + href: nunit/getting-started/dotnet-core-and-dotnet-standard.md + - name: Deprecated Features + items: + - name: AssertionHelper + href: nunit/writing-tests/AssertionHelper.md + - name: ListMapper + href: nunit/writing-tests/ListMapper.md + - name: Addin Replacement in the Framework + href: nunit/technical-notes/usage/Addin-Replacement-in-the-Framework.md + - name: Visual Studio Support + href: nunit/technical-notes/usage/Visual-Studio-Support.md + - name: NUnit Xamarin Runners + href: xamarin-runners/toc.yml + topicHref: xamarin-runners/index.md + - name: VS Test Generator + href: vs-test-generator/toc.yml + topicHref: vs-test-generator/Visual-Studio-Test-Generator.md + - name: NUnit Project Editor + href: https://github.com/nunit-legacy/nunit-project-editor/wiki/Project-Editor + - name: Older Release Notes + items: + - name: Test Adapter V3 + href: vs-test-adapter/AdapterV3-Release-Notes.md + - name: Test Adapter V2 + href: vs-test-adapter/AdapterV2-Release-Notes.md + - name: Test Generator VS2017/VS2019 + href: vs-test-generator/TestGenerator-Release-Notes-VS2017-VS2019.md + - name: Test Generator VS2015 + href: vs-test-generator/TestGenerator-Release-Notes-VS2015.md + - name: Developer History + items: + - name: Notes Toward NUnit 4.0 + href: developer-info/Notes-Toward-NUnit-4.0.md + - name: NUnit 3.0 Architecture (2009) + href: nunit/technical-notes/nunit-internals/NUnit-3.0-Architecture-(2009).md + - name: Packaging the V2 Adapter + href: developer-info/Packaging-the-V2-Adapter.md + - name: Packaging the Installer + href: developer-info/Packaging-the-Installer.md diff --git a/docs/articles/vs-test-adapter/Debugging.md b/docs/articles/vs-test-adapter/Debugging.md index 46b84f54c..67b286925 100644 --- a/docs/articles/vs-test-adapter/Debugging.md +++ b/docs/articles/vs-test-adapter/Debugging.md @@ -44,6 +44,9 @@ section. A detailed explanation of the process can be found in [this blog post](https://hermit.no/debugging-the-nunit3testadapter-take-2/) +To step into the adapter source code from your own debugging session, see +[Adapter Source Stepping](Adapter-Source-Stepping.md). + ## Debugging earlier versions See [this blog post](https://hermit.no/debugging-the-nunit3testadapter/) for details on that process. diff --git a/docs/articles/vs-test-adapter/Index.md b/docs/articles/vs-test-adapter/Index.md index 2f11e8f44..8a28b61b7 100644 --- a/docs/articles/vs-test-adapter/Index.md +++ b/docs/articles/vs-test-adapter/Index.md @@ -1,24 +1,42 @@ # Visual Studio Test Adapter -The NUnit 3 Test Adapter allows you to run NUnit 3 and 4 tests inside Visual Studio or with `dotnet` on the command line. +The NUnit Test Adapter lets you run NUnit tests in Visual Studio, Rider and Visual Studio Code, and from the command +line with `dotnet test`. It runs tests written with NUnit 3, NUnit 4 and NUnit 5. -The current release is designed to work with Visual Studio 2012, 2013, 2015, 2017, 2019 and 2022. Some features are not -available under VS2012 RTM. It also works from the command line using either `vstest.console` or `dotnet test`. +The adapter is published on NuGet as **NUnit3TestAdapter**. The name comes from the NUnit 3 era; the same package is +used for all current NUnit versions. -The current release works with .net framework 3.5 and higher, with .net core `3.*`, and with .net 5, .net 6, and .net 7. +* [Download released versions](https://www.nuget.org/packages/NUnit3TestAdapter/) +* [Download pre-release versions](https://www.myget.org/feed/nunit/package/nuget/NUnit3TestAdapter) -Releases of Visual Studio prior to VS 2012 did not have the ability to directly run tests built with Open Source testing -frameworks like NUnit. +## Getting started -[Download Released versions](https://www.nuget.org/packages/NUnit3TestAdapter/) +Add the adapter as a NuGet package to each test project. The NUnit project templates in Visual Studio, Rider and +`dotnet new nunit` already include it. See [Installation](xref:vstestadapterinstallation) for how to add it to an +existing project, and [Usage](Usage.md) for running and debugging tests in Visual Studio. -[Download Pre-release versions](https://www.myget.org/feed/nunit/package/nuget/NUnit3TestAdapter) +## Two ways to run tests -The adapter is delivered as a nuget package to be installed into all test projects. +The adapter supports both test platforms that `dotnet test` and the IDEs use: -> [!NOTE] -> Up to version 3.17 there is also a VSIX extension version, which was used earlier for Visual Studio up to -> version 2019. The support for this has been deprecated, and the existing VSIX version does not work for VS 2022. The -> recommendation is to avoid this altogether and use the nuget version. It is not possible to run NUnit 2.x tests using -> this adapter. Use the original adapter for that purpose. If you need to work with projects using NUnit 2.x and other -> projects using NUnit 3, you may install both versions of the adapter. +* **VSTest**, the classic test platform. This is the default. +* **[Microsoft.Testing.Platform](NUnit-And-Microsoft-Test-Platform.md)** (MTP), the newer and lighter test platform. + From adapter version 6.0, MTP version 2 is supported. + +## Supported .NET versions + +The current adapter, version 6, runs tests on .NET Framework 4.6.2 and later, and on .NET 8 and later. Older .NET +versions, such as .NET Core 3.1 and .NET 5 to 7, need an older adapter version. See +[Supported Frameworks](Supported-Frameworks.md) for which adapter version supports which .NET version. + +## Configuration + +Use a `.runsettings` file, or settings on the `dotnet test` command line, to control how the adapter runs your tests: +test filters, output, parallel execution, result files and more. See +[Configuration with runsettings](xref:tipsandtricks) for all the settings. + +## Older versions + +* The adapter can't run NUnit 2.x tests. Those need the NUnit 2 adapter, which is no longer maintained. +* Up to version 3.17, the adapter was also available as a VSIX extension for Visual Studio 2019 and earlier. The VSIX + version is deprecated and doesn't work with Visual Studio 2022 or later. Use the NuGet package instead. diff --git a/docs/articles/vs-test-adapter/toc.yml b/docs/articles/vs-test-adapter/toc.yml index 6fe6f01fd..841cc6da1 100644 --- a/docs/articles/vs-test-adapter/toc.yml +++ b/docs/articles/vs-test-adapter/toc.yml @@ -24,9 +24,5 @@ href: Adapter-Source-Stepping.md - name: Release Notes V4 href: AdapterV4-Release-Notes.md -- name: Release Notes V3 - href: AdapterV3-Release-Notes.md -- name: Release Notes V2 - href: AdapterV2-Release-Notes.md - name: License href: Adapter-License.md diff --git a/docs/articles/vs-test-generator/toc.yml b/docs/articles/vs-test-generator/toc.yml index 48142bc00..448a9004c 100644 --- a/docs/articles/vs-test-generator/toc.yml +++ b/docs/articles/vs-test-generator/toc.yml @@ -3,8 +3,4 @@ - name: Installation href: TestGenerator-Installation.md - name: Release Notes - href: TestGenerator-Release-Notes.md -- name: Release Notes VS2017/VS2019 - href: TestGenerator-Release-Notes-VS2017-VS2019.md -- name: Release Notes VS2015 - href: TestGenerator-Release-Notes-VS2015.md \ No newline at end of file + href: TestGenerator-Release-Notes.md \ No newline at end of file diff --git a/docs/classic.md b/docs/classic.md new file mode 100644 index 000000000..0c2ff9448 --- /dev/null +++ b/docs/classic.md @@ -0,0 +1,24 @@ +# NUnit Documentation Site + +> [!NOTE] +> This is the previous home page of the NUnit documentation, kept for a while for reference. The documentation now +> starts at the [new home page](index.md). Feedback is welcome in +> [this discussion](https://github.com/nunit/docs/discussions/1023). + +This web site contains the documentation for all active NUnit projects as well as developer documentation for those +working on NUnit or wishing to do so. + +## User Documentation + +* [NUnit](xref:intro) covers the core tools of NUnit, including the framework, NUnitLite, and the console runner. +* [NUnit VS Adapter](xref:vstestadapterinstallation) covers the test adapters for Visual Studio and .Net. +* [NUnit Analyzers](xref:nunitanalyzers) covers the NUnit Analyzers. +* [NUnit VS Test Generator](xref:vstestgenerator) covers the Visual Studio extension for generating tests in both NUnit + V2 and V3. +* [NUnit Xamarin Runners](xref:xamarinrunners) covers the NUnit test runners for Xamarin and mobile devices. +* [NUnit Engine](xref:nunitengine) covers the NUnit Engine, the central component all test runners are built around. + +## Developer Documentation + +* [Team practices](xref:teampractices) describe how NUnit works and how our teams work. +* [Specifications](xref:specifications) are descriptions of features we plan to add. diff --git a/docs/custom_template/styles/main.css b/docs/custom_template/styles/main.css index 92ddd9c42..cd4dcf1a0 100644 --- a/docs/custom_template/styles/main.css +++ b/docs/custom_template/styles/main.css @@ -9,4 +9,132 @@ div.across ul li float:left; display:block; width:9em -} \ No newline at end of file +} +/* ------------------------------------------------------------------ + Documentation home page (index.md). Everything is scoped under .nh so the + rest of the site is unaffected. + ------------------------------------------------------------------ */ +.nh { + --nh-green: #005b0c; + --nh-green-dark: #003d08; + --nh-green-soft: #e8f3ea; + --nh-ink: #1b1f23; + --nh-muted: #57606a; + --nh-border: #d8dee4; + --nh-surface: #ffffff; + --nh-radius: 12px; + color: var(--nh-ink); + font-size: 15px; + line-height: 1.55; + margin-bottom: 48px; +} +.nh a { text-decoration: none; } +.nh h1, .nh h2, .nh h3 { font-weight: 600; letter-spacing: -0.01em; } +.nh code { background: var(--nh-green-soft); color: var(--nh-green-dark); padding: 1px 5px; border-radius: 4px; } + + +/* Hero */ +.nh-hero { + display: grid; grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr); gap: 32px; align-items: center; + padding: 40px; border-radius: 16px; color: #fff; + background: + radial-gradient(circle at 85% 15%, rgba(255, 255, 255, .12), transparent 45%), + linear-gradient(135deg, var(--nh-green-dark) 0%, var(--nh-green) 55%, #0a7a3b 100%); +} +.nh-eyebrow { margin: 0 0 8px; font-size: 13px; font-weight: 700; letter-spacing: .08em; text-transform: uppercase; opacity: .8; } +.nh-hero h1 { margin: 0 0 16px; font-size: 40px; line-height: 1.15; color: #fff; } +.nh-lead { font-size: 17px; margin: 0 0 24px; opacity: .92; max-width: 36em; } +.nh-actions { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: 24px; } +.nh-btn { + display: inline-block; padding: 9px 18px; border-radius: 8px; font-weight: 600; + color: #fff !important; border: 1px solid rgba(255, 255, 255, .45); transition: background .15s; +} +.nh-btn:hover, .nh-btn:focus { background: rgba(255, 255, 255, .12); } +.nh-btn-primary { background: #fff; border-color: #fff; color: var(--nh-green-dark) !important; } +.nh-btn-primary:hover, .nh-btn-primary:focus { background: var(--nh-green-soft); } +.nh-popular { margin: 0; font-size: 13px; display: flex; flex-wrap: wrap; gap: 6px; align-items: center; } +.nh-popular span { opacity: .75; margin-right: 2px; } +.nh-popular a { + color: #fff; background: rgba(255, 255, 255, .12); padding: 3px 10px; border-radius: 999px; + border: 1px solid rgba(255, 255, 255, .2); +} +.nh-popular a:hover, .nh-popular a:focus { background: rgba(255, 255, 255, .22); } +.nh-hero-code { + background: #fff; border-radius: 10px; overflow: hidden; + box-shadow: 0 18px 40px rgba(0, 0, 0, .25); +} +.nh-code-title { + display: flex; align-items: center; gap: 6px; padding: 8px 12px; + background: #f3f5f7; border-bottom: 1px solid var(--nh-border); color: var(--nh-muted); font-size: 12px; +} +.nh-code-title span { width: 10px; height: 10px; border-radius: 50%; background: #d0d7de; } +.nh-code-title span:nth-child(3) { margin-right: 6px; } +.nh-hero-code { min-width: 0; } +.nh-hero-code pre { overflow-x: auto; word-wrap: normal; white-space: pre; margin: 0; border: 0; border-radius: 0; background: #fff; font-size: 13px; } +.nh-hero-code pre code { white-space: pre; word-wrap: normal; background: none; color: inherit; padding: 0; } + +/* Sections */ +.nh-section { margin-top: 40px; } +.nh-grid { display: grid; gap: 16px; } +.nh-grid-3 { grid-template-columns: repeat(3, minmax(0, 1fr)); grid-auto-flow: row dense; } + +/* Cards */ +.nh-card { + background: var(--nh-surface); border: 1px solid var(--nh-border); border-radius: var(--nh-radius); + padding: 20px; transition: border-color .15s, box-shadow .15s; +} +.nh-card:hover, .nh-card:focus-within { + border-color: var(--nh-green); box-shadow: 0 6px 20px rgba(0, 91, 12, .12); +} +.nh-card h2 { font-size: 18px; margin: 12px 0 4px; } +.nh-card h2 a { color: var(--nh-ink); } +.nh-card h2 a:hover { color: var(--nh-green); } +.nh-card h3 { + font-size: 12px; font-weight: 700; text-transform: uppercase; letter-spacing: .06em; + color: var(--nh-muted); margin: 16px 0 6px; +} +.nh-card p { color: var(--nh-muted); margin: 0 0 12px; } +.nh-card ul { list-style: none; padding: 0; margin: 0; } +.nh-card li { padding: 3px 0; } +.nh-card li a { color: var(--nh-green); } +.nh-card li a::before { content: "\203A"; margin-right: 8px; opacity: .6; } +.nh-card li a:hover { text-decoration: underline; } + +/* Writing tests is the main message, so it gets the tall, highlighted card */ +.nh-card-featured { + grid-row: span 2; border: 2px solid var(--nh-green); + background: linear-gradient(180deg, var(--nh-green-soft) 0%, var(--nh-surface) 55%); +} +.nh-card-featured h2 { font-size: 22px; } +.nh-card-featured > ul:first-of-type li { padding: 5px 0; font-size: 16px; font-weight: 600; } + +.nh-icon { + display: inline-flex; align-items: center; justify-content: center; + width: 40px; height: 40px; border-radius: 10px; background: var(--nh-green-soft); +} +.nh-card-featured .nh-icon { background: var(--nh-green); } +.nh-card-featured .nh-icon svg { stroke: #fff; } +.nh-icon svg { + width: 22px; height: 22px; fill: none; stroke: var(--nh-green); + stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; +} + +.nh-community { margin-top: 32px; text-align: center; color: var(--nh-muted); } +.nh-community a { color: var(--nh-green); font-weight: 600; } + +@media (max-width: 991px) { + .nh-hero { grid-template-columns: minmax(0, 1fr); padding: 28px 20px; } + .nh-hero h1 { font-size: 30px; } + .nh-grid-3 { grid-template-columns: repeat(2, minmax(0, 1fr)); } +} +@media (max-width: 600px) { + .nh-grid-3 { grid-template-columns: minmax(0, 1fr); } + .nh-card-featured { grid-row: auto; } +} +@media (prefers-reduced-motion: reduce) { + .nh-card, .nh-btn { transition: none; } +} + +/* Archive: a low-key, full-width strip at the bottom */ +.nh-card-wide { grid-column: 1 / -1; background: #f6f8fa; } +.nh-card-wide ul { columns: 3 220px; column-gap: 24px; } diff --git a/docs/index.md b/docs/index.md index 95e51e032..6a25d3919 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,19 +1,194 @@ -# NUnit Documentation Site - -This web site contains the documentation for all active NUnit projects as well as developer documentation for those -working on NUnit or wishing to do so. - -## User Documentation - -* [NUnit](xref:intro) covers the core tools of NUnit, including the framework, NUnitLite, and the console runner. -* [NUnit VS Adapter](xref:vstestadapterinstallation) covers the test adapters for Visual Studio and .Net. -* [NUnit Analyzers](xref:nunitanalyzers) covers the NUnit Analyzers. -* [NUnit VS Test Generator](xref:vstestgenerator) covers the Visual Studio extension for generating tests in both NUnit - V2 and V3. -* [NUnit Xamarin Runners](xref:xamarinrunners) covers the NUnit test runners for Xamarin and mobile devices. -* [NUnit Engine](xref:nunitengine) covers the NUnit Engine, the central component all test runners are built around. - -## Developer Documentation - -* [Team practices](xref:teampractices) describe how NUnit works and how our teams work. -* [Specifications](xref:specifications) are descriptions of features we plan to add. +--- +title: NUnit Documentation +_disableAffix: true +_disableContribution: true +_description: Documentation for NUnit, the open-source unit-testing framework for all .NET languages. +--- + + +
+
+
+

NUnit documentation

+

Write tests you can trust, for any .NET code

+

NUnit is the open-source unit-testing framework for .NET. Write a test in a few lines, get warnings about mistakes as you type from the NUnit Analyzers, run it with many sets of data, and run it anywhere: in Visual Studio, Rider, VS Code, on the command line or in your build pipeline.

+ + +
+
+
CalculatorTests.cs
+
using NUnit.Framework;
+public class CalculatorTests
+{
+    [TestCase(2, 3, 5)]
+    [TestCase(-1, 1, 0)]
+    public void Add_ReturnsSum(int a, int b, int expected)
+    {
+        var result = new Calculator().Add(a, b);
+        Assert.That(result, Is.EqualTo(expected));
+    }
+}
+
+
+
+
+ +
+ +

Getting started

+

Create a test project in the tool you already use, or add NUnit to an existing one.

+ +
+ + + + + + + +
+
+

Questions? Ask in GitHub Discussions · NUnit on GitHub · Help improve these docs · License

+
diff --git a/docs/snippets/Snippets.NUnit/SetUpTearDownGuideExamples.cs b/docs/snippets/Snippets.NUnit/SetUpTearDownGuideExamples.cs new file mode 100644 index 000000000..5b0c23523 --- /dev/null +++ b/docs/snippets/Snippets.NUnit/SetUpTearDownGuideExamples.cs @@ -0,0 +1,134 @@ +using NUnit.Framework; + +#pragma warning disable CA1822 + +namespace Snippets.NUnit.SetUpTearDownGuide.PerTest +{ + #region PerTestSetUpTearDown + public class ReportWriterTests + { + private string _folder = null!; + + [SetUp] + public void CreateFolder() + { + // Runs before each test, so every test gets its own empty folder. + _folder = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()); + Directory.CreateDirectory(_folder); + } + + [TearDown] + public void DeleteFolder() + { + // Runs after each test, also when the test failed. + if (Directory.Exists(_folder)) + Directory.Delete(_folder, recursive: true); + } + + [Test] + public void Write_CreatesReportFile() + { + File.WriteAllText(Path.Combine(_folder, "report.txt"), "Hello"); + Assert.That(Directory.GetFiles(_folder), Has.Length.EqualTo(1)); + } + + [Test] + public void Folder_StartsEmpty() + { + Assert.That(Directory.GetFiles(_folder), Is.Empty); + } + } + #endregion +} + +namespace Snippets.NUnit.SetUpTearDownGuide.PerFixture +{ + public sealed class ProductCatalog : IDisposable + { + public static ProductCatalog LoadFromDatabase() => new(); + public IReadOnlyList Products { get; } = ["Apple", "Banana", "Cherry"]; + public void Dispose() { } + } + + public class ShoppingCart + { + private readonly List _items = []; + public IReadOnlyList Items => _items; + public void Add(string product) => _items.Add(product); + } + + #region PerFixtureOneTimeSetUp + public class ShoppingCartTests + { + private ProductCatalog _catalog = null!; + private ShoppingCart _cart = null!; + + [OneTimeSetUp] + public void LoadCatalog() + { + // Expensive, and only read by the tests: create it once for all of them. + _catalog = ProductCatalog.LoadFromDatabase(); + } + + [OneTimeTearDown] + public void DisposeCatalog() + { + _catalog.Dispose(); + } + + [SetUp] + public void CreateCart() + { + // Cheap, and the tests change it: create a fresh one for each test. + _cart = new ShoppingCart(); + } + + [Test] + public void Add_PutsProductInCart() + { + _cart.Add(_catalog.Products[0]); + Assert.That(_cart.Items, Has.Count.EqualTo(1)); + } + + [Test] + public void NewCart_IsEmpty() + { + Assert.That(_cart.Items, Is.Empty); + } + } + #endregion +} + +#region SetUpFixtureForNamespace +namespace Snippets.NUnit.SetUpTearDownGuide.Integration +{ + [SetUpFixture] + public class IntegrationTestEnvironment + { + public static string ConnectionString { get; private set; } = ""; + + [OneTimeSetUp] + public void StartServices() + { + // Runs once, before any test in this namespace and its child namespaces. + ConnectionString = "Server=localhost;Database=Tests"; + } + + [OneTimeTearDown] + public void StopServices() + { + // Runs once, after all tests in this namespace have finished. + ConnectionString = ""; + } + } + + public class OrderRepositoryTests + { + [Test] + public void ConnectionString_IsAvailable() + { + Assert.That(IntegrationTestEnvironment.ConnectionString, Does.Contain("Database=Tests")); + } + } +} +#endregion diff --git a/docs/snippets/Snippets.NUnit/WritingTestsGuideExamples.cs b/docs/snippets/Snippets.NUnit/WritingTestsGuideExamples.cs new file mode 100644 index 000000000..d4cfacfb8 --- /dev/null +++ b/docs/snippets/Snippets.NUnit/WritingTestsGuideExamples.cs @@ -0,0 +1,328 @@ +using NUnit.Framework; + +#pragma warning disable CA1822 + +namespace Snippets.NUnit; + +public class WritingTestsGuideExamples +{ + public class Calculator + { + public int Add(int a, int b) => a + b; + public int Multiply(int a, int b) => a * b; + } + + #region OrdinaryTest + public class CalculatorTests + { + [Test] + public void Add_TwoNumbers_ReturnsSum() + { + // Arrange + var calculator = new Calculator(); + + // Act + var result = calculator.Add(2, 3); + + // Assert + Assert.That(result, Is.EqualTo(5)); + } + } + #endregion + + #region OrdinarySetUp + public class CalculatorTestsWithSetUp + { + private Calculator _calculator = null!; + + [SetUp] + public void CreateCalculator() + { + _calculator = new Calculator(); + } + + [Test] + public void Add_ReturnsSum() + { + Assert.That(_calculator.Add(2, 3), Is.EqualTo(5)); + } + + [Test] + public void Multiply_ReturnsProduct() + { + Assert.That(_calculator.Multiply(2, 3), Is.EqualTo(6)); + } + } + #endregion + + #region DataDrivenTestCase + public class AddTests + { + [TestCase(1, 2, 3)] + [TestCase(2, 3, 5)] + [TestCase(-1, 1, 0)] + public void Add_ReturnsSum(int a, int b, int expected) + { + var result = new Calculator().Add(a, b); + Assert.That(result, Is.EqualTo(expected)); + } + } + #endregion + + #region DataDrivenExpectedResult + public class AddTestsWithExpectedResult + { + [TestCase(1, 2, ExpectedResult = 3)] + [TestCase(2, 3, ExpectedResult = 5)] + public int Add_ReturnsSum(int a, int b) + { + return new Calculator().Add(a, b); + } + } + #endregion + + #region DataDrivenTestCaseSource + public class AddTestsFromSource + { + private static IEnumerable AddCases() + { + yield return new TestCaseData(1, 2, 3).SetName("Small numbers"); + yield return new TestCaseData(1000, 2000, 3000).SetName("Large numbers"); + yield return new TestCaseData(-5, 5, 0).SetDescription("Opposites cancel out"); + } + + [TestCaseSource(nameof(AddCases))] + public void Add_ReturnsSum(int a, int b, int expected) + { + Assert.That(new Calculator().Add(a, b), Is.EqualTo(expected)); + } + } + #endregion + + #region DataDrivenValueSource + public class MultiplyByOneTests + { + private static readonly int[] Numbers = [0, 1, 42, -7]; + + [Test] + public void Multiply_ByOne_ReturnsSameNumber([ValueSource(nameof(Numbers))] int number) + { + Assert.That(new Calculator().Multiply(number, 1), Is.EqualTo(number)); + } + } + #endregion + + #region DataDrivenFixture + [TestFixture(2)] + [TestFixture(10)] + public class MultiplierTests(int multiplier) + { + [Test] + public void Multiply_ByZero_ReturnsZero() + { + Assert.That(new Calculator().Multiply(multiplier, 0), Is.Zero); + } + + [Test] + public void Multiply_ByOne_ReturnsMultiplier() + { + Assert.That(new Calculator().Multiply(multiplier, 1), Is.EqualTo(multiplier)); + } + } + #endregion + + #region AutomatingCombinatorial + public class AddIsCommutativeTests + { + [Test] + public void Add_IsCommutative([Values(-1, 0, 1)] int a, [Values(2, 3)] int b) + { + var calculator = new Calculator(); + Assert.That(calculator.Add(a, b), Is.EqualTo(calculator.Add(b, a))); + } + } + #endregion + + #region AutomatingRange + public class AddZeroTests + { + [Test] + public void Add_Zero_ReturnsSameNumber([Range(-10, 10, 5)] int number) + { + Assert.That(new Calculator().Add(number, 0), Is.EqualTo(number)); + } + } + #endregion + + #region AutomatingRandom + public class AddRandomTests + { + [Test] + public void Add_IsCommutative_ForRandomNumbers( + [Random(-1000, 1000, 5)] int a, + [Random(-1000, 1000, 5)] int b) + { + var calculator = new Calculator(); + Assert.That(calculator.Add(a, b), Is.EqualTo(calculator.Add(b, a))); + } + } + #endregion + + #region AutomatingPairwise + public class FormattingTests + { + [Test, Pairwise] + public void Format_HandlesAllOptions( + [Values("en-US", "nb-NO", "ja-JP")] string culture, + [Values(0, 1, -1)] int number, + [Values(true, false)] bool useGrouping) + { + var format = useGrouping ? "N0" : "D"; + var text = number.ToString(format, new System.Globalization.CultureInfo(culture)); + Assert.That(text, Is.Not.Empty); + } + } + #endregion + + #region DependentTests + public class OrderWorkflowTests + { + private static readonly List Orders = []; + + [Test] + public void CreateOrder() + { + Orders.Add("order-1"); + Assert.That(Orders, Has.Count.EqualTo(1)); + } + + [Test] + [DependsOnTest(nameof(CreateOrder))] + public void ShipOrder() + { + // Runs only after CreateOrder has passed. If CreateOrder fails, this test is skipped. + Assert.That(Orders, Does.Contain("order-1")); + } + + [Test] + [DependsOnTest(nameof(ShipOrder), AllowFailure = true)] + public void CleanUpOrders() + { + // Runs after ShipOrder even if it failed, so the cleanup always happens. + Orders.Clear(); + Assert.That(Orders, Is.Empty); + } + } + #endregion + + #region FlakyRetry + public class ExternalServiceTests + { + [Test] + [Retry(3)] + public void Service_Responds() + { + // If the assertion fails, NUnit runs the test again, up to 3 attempts in total. + Assert.That(CallService(), Is.EqualTo("OK")); + } + + [Test] + [Retry(3, RetryExceptions = [typeof(TimeoutException)])] + public void Service_Responds_EvenAfterTimeouts() + { + // Also retried when the call throws a TimeoutException. + Assert.That(CallService(), Is.EqualTo("OK")); + } + + private static string CallService() => "OK"; + } + #endregion + + #region FlakyRepeatThreshold + public class RecommendationTests + { + [Test] + [Repeat(20, RequiredPassPercentage = 90)] + public void Recommendation_IsUsuallyRelevant() + { + // Passes when at least 18 of the 20 runs pass. + Assert.That(GetRecommendation(), Is.Not.Empty); + } + + private static string GetRecommendation() => "NUnit"; + } + #endregion + + #region SlowMaxTime + public class PerformanceTests + { + [Test] + [MaxTime(2000, WarningTime = 500)] + public void Search_IsFastEnough() + { + // A warning above 500 ms, a failure above 2 seconds. The test is never interrupted. + var result = Enumerable.Range(1, 1000).Where(n => n % 7 == 0).ToList(); + Assert.That(result, Is.Not.Empty); + } + } + #endregion + + #region SlowCancelAfter + public class DownloadTests + { + [Test] + [CancelAfter(5000)] + public async Task Download_Completes(CancellationToken cancellationToken) + { + // NUnit cancels the token after 5 seconds. Pass it on so the work actually stops. + var content = await DownloadAsync(cancellationToken); + Assert.That(content, Is.Not.Empty); + } + + private static async Task DownloadAsync(CancellationToken cancellationToken) + { + await Task.Delay(10, cancellationToken); + return "content"; + } + } + #endregion + + #region OrganizingCategories + [Category("Integration")] + public class DatabaseTests + { + [Test] + public void Connection_Opens() + { + Assert.Pass(); + } + + [Test] + [Category("Slow")] + public void Migration_Runs() + { + // This test is in both the "Integration" and the "Slow" category. + Assert.Pass(); + } + } + #endregion + + #region OrganizingExplicitIgnore + public class MaintenanceTests + { + [Test] + [Explicit("Rebuilds the test database, run it on demand")] + public void RebuildTestDatabase() + { + Assert.Pass(); + } + + [Test] + [Ignore("Waiting for issue #123 to be fixed", Until = "2099-12-31")] + public void Export_HandlesUnicode() + { + Assert.Fail("Not fixed yet"); + } + } + #endregion +} diff --git a/docs/toc.yml b/docs/toc.yml index 4aa0b672c..6f7c56bc6 100644 --- a/docs/toc.yml +++ b/docs/toc.yml @@ -1,4 +1,6 @@ -- name: Articles - href: articles/ -- name: API Reference - href: api/ \ No newline at end of file +- name: Articles + href: articles/ +- name: API Reference + href: api/ +- name: Classic Home + href: classic.md