بنقرة واحدة
jaribu
Write tests using the Jaribu framework for .NET 10 file-based apps (runfiles)
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
القائمة
Write tests using the Jaribu framework for .NET 10 file-based apps (runfiles)
التثبيت باستخدام Codex أو Claude انسخ هذا Prompt والصقه في Codex أو Claude أو مساعد آخر ليراجع صفحة Skill ويثبّتها لك.
استنادا إلى تصنيف SOC المهني
| name | jaribu |
| description | Write tests using the Jaribu framework for .NET 10 file-based apps (runfiles) |
Jaribu is an attribute-based testing framework for .NET 10 runfiles. Tests are standalone executables.
Jaribu uses a sink-based architecture where all test output flows through ITestResultSink:
TestRunner.RunTestsAsync(sink)
├── TerminalSink → Console output (dotnet run single-file)
├── MtpSink → IMessageBus → VS/Rider/dotnet test
└── NullSink → Silent (testing/benchmarking)
| Type | Purpose |
|---|---|
TestNodeState | Enum: Discovered, InProgress, Passed, Failed, Skipped, Timeout, Error, Cancelled |
TestNodeInfo | Record: Uid, DisplayName, State, Duration?, Exception?, Message?, Parameters? |
TestRunStats | Record: ClassName, StartTime, Duration, PassedCount, FailedCount, SkippedCount |
ITestResultSink | Interface for receiving test lifecycle events |
#!/usr/bin/dotnet --
#if !JARIBU_MULTI
return await RunAllTests();
#endif
namespace Your.Namespace.Here
{
[TestTag("CategoryName")]
public class YourTestClassName
{
[ModuleInitializer]
internal static void Register() => RegisterTests<YourTestClassName>();
public static async Task Should_describe_expected_behavior()
{
// Arrange
// Act
// Assert
await Task.CompletedTask;
}
}
} // namespace Your.Namespace.Here
public static async TaskUse a hierarchical SUT_Action_Given_Should_Result pattern:
| Element | Location | Example |
|---|---|---|
| SUT (System Under Test) | Namespace | ShellBuilder_ |
| Action (method being tested) | Class (prefix) | CaptureAsync_Given_ |
| Given (precondition/scenario) | Method (prefix) | EchoCommand_ |
| Result (expected outcome) | Method (suffix) | Should_CaptureStdout |
Full qualified test name: ShellBuilder_.CaptureAsync_Given_.EchoCommand_Should_CaptureStdout
namespace ShellBuilder_
{
[TestTag("Core")]
public class CaptureAsync_Given_
{
[ModuleInitializer]
internal static void Register() => RegisterTests<CaptureAsync_Given_>();
public static async Task EchoCommand_Should_CaptureStdout()
{
CommandOutput output = await Shell.Builder("echo").WithArguments("Hello").CaptureAsync();
output.Stdout.Trim().ShouldBe("Hello");
}
public static async Task MultipleArgs_Should_PassAllArgs()
{
CommandOutput output = await Shell.Builder("echo").WithArguments("a", "b").CaptureAsync();
output.Stdout.Trim().ShouldBe("a b");
}
}
public class WithArguments_Given_
{
[ModuleInitializer]
internal static void Register() => RegisterTests<WithArguments_Given_>();
public static async Task EmptyArray_Should_ExecuteWithNoArgs()
{
// ...
}
}
}
Called automatically before/after EACH test:
public static async Task Setup()
{
// Called before EACH test
await Task.CompletedTask;
}
public static async Task CleanUp()
{
// Called after EACH test (even if test fails)
await Task.CompletedTask;
}
[Input("value1")]
[Input("value2")]
[Input("value3")]
public static async Task Should_handle_input(string input)
{
// Runs once per [Input] attribute
await Task.CompletedTask;
}
| Attribute | Purpose |
|---|---|
[TestTag("Name")] | Tag for filtering (class or method) |
[Skip("reason")] | Skip test with reason |
[Timeout(ms)] | Set timeout in milliseconds |
[Input("value")] | Data-driven test input |
[ModuleInitializer] | Register class for multi-mode |
[ClearRunfileCache] | Clear cache (standalone only, removed) |
result.ShouldBe(expected);
result.ShouldNotBe(unexpected);
result.ShouldBeNull();
result.ShouldNotBeNull();
flag.ShouldBeTrue();
flag.ShouldBeFalse();
count.ShouldBeGreaterThan(0);
text.ShouldContain("substring");
text.ShouldStartWith("prefix");
text.ShouldBeEmpty();
list.ShouldContain(item);
Should.Throw<Exception>(() => ThrowingMethod());
Format: {sut}.{action}.cs (kebab-case)
This aligns with the naming convention - one file per Action keeps files small and token-efficient.
Examples:
shell-builder.capture-async.cs # ShellBuilder_.CaptureAsync_Given_.*
shell-builder.to-command-string.cs # ShellBuilder_.ToCommandString_Given_.*
shell-builder.pipe.cs # ShellBuilder_.Pipe_Given_.*
shell-builder.run-async.cs # ShellBuilder_.RunAsync_Given_.*
Why one file per Action?
# Make executable and run (Runfile Mode)
chmod +x my-test.cs
./my-test.cs
# Or with dotnet
dotnet run my-test.cs
# Filter by tag
JARIBU_FILTER_TAG=Lexer ./my-test.cs
# M.T.P. Mode (IDE integration, dotnet test)
dotnet test
# List discovered tests
dotnet run -- --list-tests
// Simple usage - returns exit code (backward compatible)
int exitCode = await TestRunner.RunTests<MyTests>();
// Sink-based - get stats with console output
using TerminalSink sink = new();
TestRunStats stats = await TestRunner.RunTestsAsync<MyTests>(sink);
// Silent execution - for programmatic use
TestRunStats stats = await TestRunner.RunTestsAsync<MyTests>(NullSink.Instance);
// Non-generic - for reflection-based execution
TestRunStats stats = await TestRunner.RunTestsAsync(typeof(MyTests), sink);
<ItemGroup>
<PackageReference Include="TimeWarp.Jaribu" />
<PackageReference Include="Shouldly" />
</ItemGroup>
<ItemGroup>
<Using Include="Shouldly" />
<Using Include="System.Console" Static="true" />
<Using Include="TimeWarp.Jaribu" />
<Using Include="TimeWarp.Jaribu.TestRunner" Static="true" />
</ItemGroup>
/tmp directorytests/ directory in the projecttemp- (e.g., temp-test-which.cs)Tests exist to expose bugs. A failing test is doing its job.
NEVER:
When a test fails:
Valid reasons to skip:
DO:
Should_ namesDON'T: