Skip to content

concepts.md

Ulf Bourelius edited this page Sep 19, 2025 · 2 revisions

🧠 Concepts — Zentient.Testing (Alpha)

Core mental models, terminology, and design principles for the 0.1.x alpha release.


1️⃣ Mission & Scope

Mission:
Provide a DX‑first, minimal‑ceremony toolkit for writing Arrange → Act → Assert tests without requiring a full DI container or external mocking framework.

Scope in Alpha:

  • Core scenario DSL (ITestScenario)
  • Lightweight, per‑test harness (ITestHarness)
  • Built‑in minimal mock engine (IMockBuilder)
  • Fluent result assertions (IResultAssertions)
  • No dependency on Zentient.DependencyInjection yet
  • No adapters — mocking and DI are internal only

2️⃣ Guiding Principles

  • DX‑first — APIs are terse, discoverable, and read like the test flow.
  • Non‑invasive — Public API does not expose concrete DI/mocking framework types.
  • Test‑scoped isolation — Each test gets its own harness; all resources disposed after use.
  • Fail‑fast diagnostics — Exceptions are descriptive and actionable.
  • Progressive enhancement — Alpha focuses on core flow; DI adapters, analyzers, and advanced diagnostics come later.

3️⃣ Core Abstractions

ITestScenario<TInput, TResult>

The orchestrator for a single test scenario.

ITestScenario<TInput, TResult> Arrange(Action<ITestHarnessBuilder> configure);
Task<TResult> ActAsync(TInput input, CancellationToken ct = default);
ITestScenario<TInput, TResult> Assert(Action<IResultAssertions<TResult>> assertions);
  • Arrange — Configure dependencies and mocks.
  • ActAsync — Execute the system under test (SUT) using harness resolution rules.
  • Assert — Verify the result with fluent assertions.

ITestHarnessBuilder

Configures the per‑scenario harness.

  • WithDependency<TService>(TService instance) — Register a concrete instance.
  • WithMock<TService>(Action<IMockBuilder<TService>> configure) — Configure a mock.
  • Replace<TService>(TService instance) — Replace an existing registration.
  • Build() — Produce the harness (internal type in alpha).

IMockBuilder<TService>

Minimal built‑in mock DSL.

mb.Given(s => s.Do(It.IsAny<int>())).ThenReturns(42);
mb.Given(s => s.Do("bad")).ThenThrows(new InvalidOperationException("boom"));
  • Given(...) — Identify a method/property call to stub.
  • ThenReturns(...) — Return a specified value.
  • ThenThrows(...) — Throw a specified exception.

IResultAssertions<TResult>

Fluent assertions for scenario results.

  • NotBeNull()
  • HaveValue(TResult expected)
  • With<TProperty>(Expression<Func<TResult, TProperty>> selector, TProperty expected)
  • Supports chaining via .And

ITestHarness (internal in alpha)

  • Lightweight service registry: Type → instance
  • Resolution rules:
    1. Return registered instance if found.
    2. Otherwise, construct via reflection if all constructor parameters are registered.
    3. Otherwise, throw descriptive exception.

4️⃣ Default Behaviors

  • SUT Resolution — Prefers explicit registrations; falls back to reflection‑based construction.
  • Mocks — Stored behaviors keyed by expression; return configured values or throw.
  • Context — No typed IContext yet; use WithDependency for contextual data.

5️⃣ Example Flow

var scenario = TestScenario.ForHandler<MyHandler, string, string>(
    (h, input, ct) => Task.FromResult(h.Handle(input))
);

scenario.Arrange(b => b.WithMock<IMyService>(mb =>
    mb.Given(s => s.Do(It.IsAny<string>())).ThenReturns("mocked")
));

var result = await scenario.ActAsync("in");

scenario.Assert(a => a.HaveValue("mocked"));

6️⃣ Out of Scope for Alpha

  • No external DI container integration.
  • No mocking framework adapters.
  • No typed context or envelope abstractions.
  • No diagnostics API or analyzers.

7️⃣ Looking Ahead

The Beta release will add:

  • Integration with Zentient.DependencyInjection
  • Hosting adapters (e.g., Microsoft DI)
  • Mock adapters (e.g., Moq)
  • Basic DI diagnostics

🔗 Related Pages

📚 Zentient.Testing Docs

Quick links to all major sections of the documentation.


📄 Overview

🧠 Core Concepts

🚀 Getting Started

📑 Reference

🛠 Development


💡 Tip: Use the Architecture page as your hub — it links to Getting Started, Usage Examples, API Reference, and Concepts.

Clone this wiki locally