Skip to content

Commit 6f5ca86

Browse files
committed
Update Docs
1 parent 44f94f0 commit 6f5ca86

4 files changed

Lines changed: 69 additions & 6 deletions

File tree

.github/copilot-instructions.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@ It wraps and extends mocking providers (currently Moq, with planned provider‑a
1818
- `Mocker.cs` – Core mock registry and creation logic.
1919
- `MockerTestBase<T>` – Generic base for public types.
2020
- `MockerTestBase` – Non‑generic base for internal/protected types.
21+
- `MockerTestBase_Constructors.cs` – Default component creation flow, `ComponentCreationFlags`, and `ComponentConstructorParameterTypes`.
2122
- `MockerConstructionHelper` – Shared constructor resolution logic.
23+
- `ServiceProviderTestExtensions.cs` – Typed `IServiceProvider` helpers such as `CreateTypedServiceProvider(...)` and `AddServiceProvider(...)`.
2224
- `TestClassExtensions.cs` – Current verification helpers (e.g., `VerifyLogger`).
2325
- `ScenarioBuilder<T>` – Fluent scenario API (Milestone 2).
2426
- `IMockingProvider` – Provider abstraction (Milestone 1).
@@ -30,6 +32,8 @@ When generating code:
3032
- Only use Moq APIs inside `MoqProvider` or Moq‑specific test code.
3133
2. **Reuse shared helpers**
3234
- For component creation, always call `MockerConstructionHelper.CreateInstance`.
35+
- When a test must choose a constructor, prefer `MockerTestBase<TComponent>.ComponentConstructorParameterTypes` first. For direct `Mocker` usage, prefer `CreateInstanceByType(...)`. Use `CreateComponentAction` only when constructor selection cannot be expressed as a signature.
36+
- When framework code needs a real `IServiceProvider` or `IServiceScopeFactory`, prefer `CreateTypedServiceProvider(...)` or `AddServiceProvider(...)` over mocked `IServiceProvider` shims or registering only `IServiceScopeFactory` from a manually built provider.
3337
- For verification, follow the `VerifyLogger` pattern.
3438
3. **Follow naming conventions**
3539
- Public API methods: PascalCase.

docs/README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ Perfect for developers new to FastMoq. Learn the basics and write your first tes
2525
- [Provider selection and setup](./getting-started/provider-selection.md)
2626
- [Provider capabilities matrix](./getting-started/provider-capabilities.md)
2727
- [Repo-native testing guide](./getting-started/testing-guide.md)
28+
- [Typed `IServiceProvider` helpers](./getting-started/testing-guide.md#typed-iserviceprovider-helpers)
29+
- [Explicit constructor selection in tests](./getting-started/testing-guide.md#explicit-constructor-selection-in-tests)
2830
- [Web helper guidance for controller and request tests](./getting-started/testing-guide.md#controller-testing)
2931
- [Executable testing examples](./samples/testing-examples.md)
3032
- Understanding the architecture

docs/getting-started/README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ Use this table when you are deciding which package line your test project should
9292
Important package boundaries in the current v4 line:
9393

9494
`FastMoq` already includes the common end-user surface, including shared Azure SDK helpers, web, database, and Azure Functions helpers
95+
9596
- `FastMoq` also includes the FastMoq analyzer assets by default so most test projects get migration guidance without extra setup
9697
- `FastMoq.Core` stays lighter on purpose, so shared Azure SDK helpers, EF helpers, Azure Functions helpers, and web helpers are separate package decisions when you consume core directly
9798
- `FastMoq.Core` does not include analyzer assets; add `FastMoq.Analyzers` explicitly if you want analyzer guidance in a core-only package graph
@@ -379,6 +380,36 @@ public class OrderServiceTests : MockerTestBase<OrderService>
379380
}
380381
```
381382

383+
When a test needs a specific constructor, prefer the explicit constructor-selection hooks instead of relying on `GetObject<T>()` to land on the right overload.
384+
385+
- For `MockerTestBase<TComponent>`, override `ComponentConstructorParameterTypes`.
386+
- For direct `Mocker` usage, call `CreateInstanceByType<T>(...)`.
387+
- If the chosen constructor depends on `IServiceProvider` or `IServiceScopeFactory`, build and register a typed provider with `AddServiceProvider(...)` instead of extracting only `IServiceScopeFactory` from a manual `BuildServiceProvider()` call.
388+
389+
```csharp
390+
internal sealed class ArchiveInvokerTests : MockerTestBase<ArchiveInvoker>
391+
{
392+
private readonly MockFileSystem fileSystem = new();
393+
394+
protected override Action<Mocker>? SetupMocksAction => mocker =>
395+
{
396+
mocker.AddType<IFileSystem>(fileSystem, replace: true);
397+
mocker.AddServiceProvider(services =>
398+
{
399+
services.AddLogging();
400+
services.AddOptions();
401+
services.AddSingleton<IFileSystem>(fileSystem);
402+
services.AddSingleton<ArchiveService>();
403+
}, replace: true);
404+
};
405+
406+
protected override Type?[]? ComponentConstructorParameterTypes =>
407+
new Type?[] { typeof(IFileSystem), typeof(IServiceScopeFactory) };
408+
}
409+
```
410+
411+
See the [Testing Guide](./testing-guide.md#explicit-constructor-selection-in-tests) for the full constructor-selection rules and the [typed `IServiceProvider` helper guidance](./testing-guide.md#typed-iserviceprovider-helpers) for framework-heavy ServiceCollection patterns.
412+
382413
## Common Patterns
383414

384415
### Testing Constructor Parameters

docs/getting-started/testing-guide.md

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,14 @@ This guide documents the testing patterns that match FastMoq's current behavior
77
Use these rules first:
88

99
1. Use [MockerTestBase&lt;TComponent&gt;](xref:FastMoq.MockerTestBase`1) when you want FastMoq to create the component under test and manage its dependencies.
10-
2. Use [Mocks.GetOrCreateMock&lt;T&gt;()](xref:FastMoq.Mocker.GetOrCreateMock``1(FastMoq.MockRequestOptions)) when you want the normal FastMoq tracked mock path for a dependency.
11-
3. Use [AddType(...)](xref:FastMoq.Mocker.AddType``1(System.Func{FastMoq.Mocker,``0},System.Boolean,System.Object[])) when you need to replace FastMoq's default resolution with a specific concrete type, factory, or fixed instance.
12-
4. Use `CreateTypedServiceProvider(...)` and `AddServiceProvider(...)` when framework code expects a typed `IServiceProvider` rather than a one-object-for-all-types shim.
13-
5. If the constructor uses the same abstraction more than once under different DI service keys, use keyed mocks, keyed registrations, or explicit constructor injection for tests where dependency selection matters.
14-
6. Use [AddKnownType(...)](xref:FastMoq.Mocker.AddKnownType(FastMoq.KnownTypeRegistration,System.Boolean)) when a framework-style type needs special resolution or post-processing behavior.
15-
7. Use [GetMockDbContext&lt;TContext&gt;()](xref:FastMoq.DbContextMockerExtensions.GetMockDbContext``1(FastMoq.Mocker)) when testing EF Core contexts. Do not hand-roll DbContext setup unless you need behavior outside FastMoq's helper.
10+
2. If a `MockerTestBase<TComponent>` test must force a specific constructor, override `ComponentConstructorParameterTypes` first. Use `CreateComponentAction` only when the test needs custom creation logic beyond selecting a signature.
11+
3. Use [Mocks.GetOrCreateMock&lt;T&gt;()](xref:FastMoq.Mocker.GetOrCreateMock``1(FastMoq.MockRequestOptions)) when you want the normal FastMoq tracked mock path for a dependency.
12+
4. Use [AddType(...)](xref:FastMoq.Mocker.AddType``1(System.Func{FastMoq.Mocker,``0},System.Boolean,System.Object[])) when you need to replace FastMoq's default resolution with a specific concrete type, factory, or fixed instance.
13+
5. Use `CreateInstanceByType(...)` when direct `Mocker` usage must pick an exact constructor signature. Do not treat `GetObject<T>()` as the explicit constructor-selection API.
14+
6. Use `CreateTypedServiceProvider(...)` and `AddServiceProvider(...)` when framework code expects a typed `IServiceProvider` rather than a one-object-for-all-types shim.
15+
7. If the constructor uses the same abstraction more than once under different DI service keys, use keyed mocks, keyed registrations, or explicit constructor injection for tests where dependency selection matters.
16+
8. Use [AddKnownType(...)](xref:FastMoq.Mocker.AddKnownType(FastMoq.KnownTypeRegistration,System.Boolean)) when a framework-style type needs special resolution or post-processing behavior.
17+
9. Use [GetMockDbContext&lt;TContext&gt;()](xref:FastMoq.DbContextMockerExtensions.GetMockDbContext``1(FastMoq.Mocker)) when testing EF Core contexts. Do not hand-roll DbContext setup unless you need behavior outside FastMoq's helper.
1618

1719
## Core Mental Model
1820

@@ -83,6 +85,29 @@ Mocks.AddServiceProvider(services =>
8385
});
8486
```
8587

88+
`AddServiceProvider(...)` registers the typed provider itself and, when the built container exposes them, also registers `IServiceScopeFactory` and `IServiceProviderIsService` for the current `Mocker`.
89+
90+
If a constructor takes `IServiceScopeFactory`, prefer this shape:
91+
92+
```csharp
93+
var fileSystem = new MockFileSystem();
94+
95+
Mocks.AddType<IFileSystem>(fileSystem, replace: true);
96+
Mocks.AddServiceProvider(services =>
97+
{
98+
services.AddLogging();
99+
services.AddOptions();
100+
services.AddSingleton<IFileSystem>(fileSystem);
101+
services.AddSingleton<ArchiveService>();
102+
}, replace: true);
103+
104+
var scopeFactory = Mocks.GetRequiredObject<IServiceScopeFactory>();
105+
```
106+
107+
instead of building a provider manually and registering only `provider.GetRequiredService<IServiceScopeFactory>()`. Keeping the full typed provider registered makes constructor injection, nested framework resolution, and service-scope behavior stay aligned.
108+
109+
For Azure-oriented tests that also need configuration defaults, prefer `CreateAzureServiceProvider(...)` or `AddAzureServiceProvider(...)` from `FastMoq.Azure.DependencyInjection` instead of repeating `AddLogging()`, `AddOptions()`, and `IConfiguration` setup in every test.
110+
86111
Use `CreateFunctionContextInstanceServices(...)` and `AddFunctionContextInstanceServices(...)` for Azure Functions worker tests instead of hand-writing `FunctionContext.InstanceServices` plumbing:
87112

88113
```csharp
@@ -206,6 +231,7 @@ FastMoq handles constructor resolution and injection at runtime; it does not byp
206231

207232
When a test needs a specific constructor, prefer a test-side override first.
208233
That keeps constructor choice inside the test harness and avoids changing production code only to satisfy test setup.
234+
If the selected constructor depends on `IServiceProvider` or `IServiceScopeFactory`, pair the constructor-selection hook with `AddServiceProvider(...)` from the earlier typed-provider section instead of registering only a manually extracted scope factory.
209235

210236
For `MockerTestBase<TComponent>`, override `ComponentConstructorParameterTypes` when you want a specific signature but still want the default FastMoq creation path:
211237

0 commit comments

Comments
 (0)