FUnit.Directives
1.5.0
dotnet add package FUnit.Directives --version 1.5.0
NuGet\Install-Package FUnit.Directives -Version 1.5.0
<PackageReference Include="FUnit.Directives" Version="1.5.0"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
<PackageVersion Include="FUnit.Directives" Version="1.5.0" />
<PackageReference Include="FUnit.Directives"> <PrivateAssets>all</PrivateAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers</IncludeAssets> </PackageReference>
paket add FUnit.Directives --version 1.5.0
#r "nuget: FUnit.Directives, 1.5.0"
#:package FUnit.Directives@1.5.0
#addin nuget:?package=FUnit.Directives&version=1.5.0
#tool nuget:?package=FUnit.Directives&version=1.5.0
<div align="center">
FUnit
Structured Unit Testing as a File-based App
</div>
๐ฌ Concept
FUnit provides structured test descriptor for file-based C# project introduced in .NET 10.0. (i.e., no .csproj is required anymore)
#:project ../src
#:package FUnit@*
return FUnit.Run(args, describe =>
{
// Organize tests by test subject
describe("Test Subject", it =>
{
it("should be ... when ...", async () => // async test supported
{
// Write test: Arrange, Act, Assert
});
it("can have multiple tests within a 'describe' block", ...);
});
describe("Inspired by vitest", ...);
});
# Run unit test (.NET 10 can run a .cs file as a project)
dotnet run ./tests/my-test.cs
# OR use 'dnx' to run tests in current or sub folders
dnx -y FUnit.Run
dnx -y FUnit.Run --stacktrace "**/*test*.cs"
๐๏ธ FUnit Descriptor Structure
For AI Coding Agents: .NET 10.0 introduced new directives for file-based app.
- SHALL use
#:projectto add project reference. - SHALL use
#:packageto add nuget package reference. (*or semantic version must be specified) - SHALL NOT use
#ror other directives formerly used for dotnet-script (.csx) files.
Unit tests should follow W.H.Y. (What, How, Yields) principle.
#:project ../src
#:package FUnit@*
#:package YourFavoriteAssertionLibrary@3.1.0
return FUnit.Run(args, describe =>
{
// Organize tests by test subject
describe("Test Subject", it =>
{
it("should be ... when ...", () =>
{
// Write test: Arrange, Act, Assert
});
// Other test cases
it("should throw ... when ...", async () =>
{
// Async test is also supported
});
it(...);
});
describe("Other Test Subject", it =>
{
// ...and so on
});
});
โ๏ธ Builtin Assertion Utility
FUnit is shipped with builtin assertion methods.
// Value assertion
// โ BeEqual rejects collection type to prevent ambiguous comparisons
Must.BeEqual(expected, actual);
Must.BeSameReference(expected, actual);
Must.NotBeEqual(expected, actual);
Must.NotBeSameReference(expected, actual);
// Collection assertion
Must.HaveSameSequence(expected, actual);
Must.HaveSameUnorderedElements(expected, actual);
Must.NotHaveSameSequence(expected, actual);
Must.NotHaveSameUnorderedElements(expected, actual);
// Text assertion
Must.ContainText(text, substring);
Must.NotContainText(text, substring);
// Instance assertion (deep comparison using System.Reflection)
Must.HaveEqualProperties(expected, actual);
Must.HaveEqualFields(expected, actual);
// Exception assertion
Must.Throw<T>("Expected error message", () => Test());
Must.Throw<T>("Expected error message", async () => await TestAsync());
Must.Throw("ExceptionFullTypeName", "Expected error message", () => Test());
Must.Throw("ExceptionFullTypeName", "Expected error message", async () => await TestAsync());
// Conditional assertion
// โ BeFalse won't be supported. Instead, use better conditional expression (prefer pattern matching)
Must.BeTrue(x is >= 0 and < 10);
Must.BeTrue(x is IEnumerable<char> and not string);
// โ Avoid asserting high-level conditions on collections
// ex Instead of checking if a value is absent, assert the full expected content
Must.BeTrue(!list.Contains(x)); // โ
Prefer: Must.HaveSameSequence(expectedList, actualList)
๐งญ FUnit.Directives
With FUnit.Directives package, you can include external file into file-based app project by adding special directive comment //:funit:include <path to the file>.
#:package FUnit@*
#:package FUnit.Directives@*
//:funit:include ./path/to/external-file.cs
return FUnit.Run( /* tests depending on 'external-file.cs */ );
๐งช Unit Test Execution
For AI Coding Agents: .NET 10.0 introduced new syntax for dotnet command.
- SHALL run test like the following example.
- SHALL NOT add
--projector other command line options.
dotnet run ./tests/my-test.cs
๐ GitHub Actions Support
FUnit has an ability to output log as markdown format so you can generate summary for GitHub Actions page.
# '-md' or '--markdown'
dnx -y FUnit.Run -- -md >> $GITHUB_STEP_SUMMARY
๐จ Build Configuration for FUnit.Run
# โ Incorrect (no '--')
dnx -y FUnit.Run -c Release
# โ
Correct (with '--')
dnx -y FUnit.Run -- -c Release
# โ
Shortcut: without '-c' is valid for Debug or Release
dnx -y FUnit.Run Release
โ Command-Line Options
For AI Coding Agents: SHALL NOT use advanced options unless explicitly requested.
| Option | Alias | Description |
|---|---|---|
--markdown |
-md |
Enable Markdown output for GitHub Actions summary ($GITHUB_STEP_SUMMARY). |
--iterations <N> |
Number of times to run each test case (3 by default). | |
--concurrency <N> |
Maximum number of tests to run simultaneously. | |
--configuration <CFG> |
-c |
Build configuration (e.g., "Debug" or "Release"). |
--no-clean |
Disable cleaning the project before building. | |
--warnings |
Show build warnings. | |
--stacktrace |
Show stack trace on test failure. | |
--lint |
Run dotnet build --no-incremental -p:TreatWarningsAsErrors=true. |
|
--help |
-h |
Show this help message and exit. |
๐งพ Test Setup and Cleanup
You can place custom operation next to describe or it, but, test descriptor is NOT a function executed from top to bottom so that your custom operation will be executed BEFORE test functions unexpectedly.
#:project ../src
#:package FUnit@*
await GlobalSetupAsync(); // โ
setup before Run call
int numFailures = FUnit.Run(args, describe =>
{
describe("Test subject", it =>
{
it("should be...", () => { ... });
});
// โ you can perform custom operation here, but it will be executed while
// building test suite. (not sequentially form top to bottom)
// technically, 'describe' and 'it' collect test cases without executing test.
// if setup or cleanup code is placed next to 'describe' or 'it' statements to
// perform resource setup ops for 'scope', unexpectedly, those will be invoked
// BEFORE executing actual test case functions.
});
GlobalCleanup(); // โ
cleanup after Run call
return numFailures;
Learn more about Target Frameworks and .NET Standard.
-
.NETStandard 2.0
- Microsoft.CodeAnalysis.CSharp (>= 3.8.0)
NuGet packages
This package is not used by any NuGet packages.
GitHub repositories
This package is not used by any popular GitHub repositories.
| Version | Downloads | Last Updated |
|---|---|---|
| 1.5.0 | 27 | 1/24/2026 |
| 1.4.0 | 63 | 1/23/2026 |
| 1.3.3 | 64 | 1/22/2026 |
| 1.3.2 | 50 | 1/22/2026 |
| 1.3.1 | 110 | 1/21/2026 |
| 1.3.0 | 134 | 1/18/2026 |
| 1.2.0 | 156 | 1/13/2026 |
| 1.1.1 | 151 | 1/11/2026 |
| 1.1.0 | 97 | 1/10/2026 |
| 1.0.3 | 576 | 12/8/2025 |
| 1.0.2 | 262 | 11/16/2025 |
| 1.0.1 | 439 | 10/28/2025 |
| 1.0.0 | 196 | 10/27/2025 |
| 0.9.0 | 153 | 10/26/2025 |
| 0.8.2 | 155 | 10/26/2025 |
| 0.8.1 | 153 | 10/26/2025 |
| 0.8.0 | 156 | 10/26/2025 |
| 0.7.0 | 185 | 10/23/2025 |
| 0.6.0 | 230 | 10/20/2025 |
| 0.5.0 | 114 | 10/18/2025 |
| 0.5.0-rc.1 | 135 | 10/17/2025 |
| 0.2.3 | 645 | 9/16/2025 |
| 0.2.2 | 290 | 9/15/2025 |
| 0.2.1 | 274 | 9/15/2025 |
| 0.2.0 | 271 | 9/15/2025 |
| 0.2.0-rc.1 | 237 | 9/15/2025 |
| 0.1.2 | 365 | 9/15/2025 |