FUnit 1.5.0

dotnet add package FUnit --version 1.5.0
                    
NuGet\Install-Package FUnit -Version 1.5.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="FUnit" Version="1.5.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="FUnit" Version="1.5.0" />
                    
Directory.Packages.props
<PackageReference Include="FUnit" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add FUnit --version 1.5.0
                    
#r "nuget: FUnit, 1.5.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package FUnit@1.5.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=FUnit&version=1.5.0
                    
Install as a Cake Addin
#tool nuget:?package=FUnit&version=1.5.0
                    
Install as a Cake Tool

<div align="center">

FUnit

Structured Unit Testing as a File-based App

FUnit FUnit.Run FUnit.Directives <br/> test DeepWiki

</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 #:project to add project reference.
  • SHALL use #:package to add nuget package reference. (* or semantic version must be specified)
  • SHALL NOT use #r or 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 --project or 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;
Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
.NET Core netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.1 is compatible. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.1

    • No dependencies.
  • net10.0

    • No dependencies.
  • net8.0

    • No dependencies.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on FUnit:

Package Downloads
SatorImaging.Jsonable.Assertions

C# source generator for JSON serialization and deserialization.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.5.0 25 1/24/2026
1.4.0 79 1/23/2026
1.3.3 45 1/22/2026
1.3.2 33 1/22/2026
1.3.1 53 1/21/2026
1.3.0 188 1/18/2026
1.2.0 260 1/13/2026
1.1.1 108 1/11/2026
1.1.0 96 1/10/2026
1.0.3 576 12/8/2025
1.0.2 315 11/16/2025
1.0.1 480 10/28/2025
1.0.0 192 10/27/2025
0.9.0 324 10/26/2025
0.8.2 152 10/26/2025
0.8.1 144 10/26/2025
0.8.0 146 10/26/2025
0.7.0 201 10/23/2025
0.6.0 305 10/20/2025
0.5.0 112 10/18/2025
0.5.0-rc.1 235 10/17/2025
0.2.3 632 9/16/2025
0.2.2 279 9/15/2025
0.2.1 287 9/15/2025
0.2.0 287 9/15/2025
0.2.0-rc.1 216 9/15/2025
0.1.2 243 9/14/2025
0.1.1 160 9/14/2025
0.1.0 166 9/14/2025
0.1.0-rc.3 125 9/14/2025