Skip to content

sator-imaging/FUnit

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

FUnit FUnit.Run FUnit.Directives build Β  DeepWiki

πŸ”¬ Unit Testing Framework for File-based Apps

FUnit provides structured test descriptor for file-based apps 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 ...", async () =>  // async can be used
        {
            // Write actual test here: Arrange, Act, Assert
        });

        it("can have multiple test cases", ...);
    });

    describe("Inspired by vitest", ...);
});
# Run unit test
dotnet run ./tests/my-test.cs

# OR use 'dnx' to run tests in current or subfolders
dnx FUnit.Run
dnx FUnit.Run --no-clean --filter *specificTest*.cs

πŸ—ƒοΈ FUnit Descriptor Structure

Important

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.
#:project ../src
#:package FUnit@*
#:package YourFavoriteAssertionLibrary@3.1.0

return FUnit.Run(args, describe =>
{
    // Organize tests by test subject
    describe("Test Subject", it =>
    {
        // Expected result and test function
        it("should be ...", () =>
        {
            // Write actual test here: Arrange, Act, Assert
        });

        // Other test cases
        it("should not ...", async () =>
        {
            // Async test can also be written
        });

        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

Important

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 FUnit.Run -c Release

# βœ… Correct (with '--')
dnx FUnit.Run -- -c Release

# βœ… Shortcut: without '-c' is valid for Debug or Release
dnx FUnit.Run Release

βš™ Advanced Options

Important

For AI Coding Agents: SHALL NOT use advanced options unless explicitly requested.

--iterations int

# run tests 10 times (3 by default)
dotnet run ./tests/my-test.cs --iterations 10

--concurrency int (Experimental)

# run max 10 tests simultaneously subject by subject
dotnet run ./tests/my-test.cs --concurrency 10

🧾 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;

About

Unit Testing Framework for File-based Apps

Topics

Resources

License

Stars

Watchers

Forks

Sponsor this project

 

Contributors 2

  •  
  •  

Languages