diff --git a/website/.vitepress/config.ts b/website/.vitepress/config.ts index 32ead44..be37d5e 100644 --- a/website/.vitepress/config.ts +++ b/website/.vitepress/config.ts @@ -51,6 +51,15 @@ export default defineConfig({ link: 'https://www.nuget.org/packages/DependencyModules.Conventions/', }, { text: 'xUnit', link: 'https://www.nuget.org/packages/DependencyModules.xUnit/' }, + { + text: 'NSubstitute', + link: 'https://www.nuget.org/packages/DependencyModules.NSubstitute/', + }, + { text: 'Moq', link: 'https://www.nuget.org/packages/DependencyModules.Moq/' }, + { + text: 'FakeItEasy', + link: 'https://www.nuget.org/packages/DependencyModules.FakeItEasy/', + }, ], }, ], diff --git a/website/guide/testing-mocks.md b/website/guide/testing-mocks.md index ce2ddc2..1304853 100644 --- a/website/guide/testing-mocks.md +++ b/website/guide/testing-mocks.md @@ -44,8 +44,10 @@ holding. You wire nothing together yourself. Note what stayed real: `SummaryProvider` was not mocked, so the call still travels `Weather` → `SummaryProvider` → `IAiSummaryProvider`. Only the leaf was swapped. -::: tip Register the mocking library once -`[Mock]` needs a mocking framework, supplied by a separate package. Pick the one you already use: +## Choosing a mocking library + +`[Mock]` does not depend on a particular mocking library. It defines a seam, and a small package +fills it — so use whichever library you already have: | Package | Attribute | |---|---| @@ -53,25 +55,50 @@ Note what stayed real: `SummaryProvider` was not mocked, so the call still trave | `DependencyModules.Moq` | `[MoqSupport]` | | `DependencyModules.FakeItEasy` | `[FakeItEasySupport]` | +Install one and apply its attribute. Like the module attributes it works at assembly, class or +method level, and assembly is usually right: + ```shell -dotnet add package DependencyModules.NSubstitute +dotnet add package DependencyModules.Moq ``` ```csharp -[assembly: NSubstituteSupport] +[assembly: MoqSupport] ``` -Without one, `[Mock]` fails with a message telling you so. Like the module attributes it works at -assembly, class or method level; assembly is almost always right. +Without one, `[Mock]` fails with a message telling you so. -With NSubstitute and FakeItEasy the injected instance is also what you configure. Moq separates the -two, so the container gets `Mock.Object` and you reach the mock with `Mock.Get(instance)`: +### The same test in each -```csharp -Mock.Get(summaryProvider).Setup(x => x.Summarize(It.IsAny())).Returns("mild"); +Only the configuration lines differ — `[Mock]`, the injection and the assertions are identical. The +example above is NSubstitute; here are the other two: + +::: code-group + +```csharp [NSubstitute] +temperatureProvider.GetTemperature().Returns(38); +aiSummaryProvider.GetSummary().Returns("Sunny"); +``` + +```csharp [Moq] +Mock.Get(temperatureProvider).Setup(x => x.GetTemperature()).Returns(38); +Mock.Get(aiSummaryProvider).Setup(x => x.GetSummary()).Returns("Sunny"); +``` + +```csharp [FakeItEasy] +A.CallTo(() => temperatureProvider.GetTemperature()).Returns(38); +A.CallTo(() => aiSummaryProvider.GetSummary()).Returns("Sunny"); ``` + ::: +The `Mock.Get` in the Moq version is the one difference worth knowing about. NSubstitute and +FakeItEasy hand you an object that *is* the mock, so the parameter the container injected is the +thing you configure. Moq keeps the two apart — the container receives `Mock.Object`, and +`Mock.Get(instance)` gets you back to the `Mock` to set expectations on. + +Unconfigured members return `default` rather than throwing, in all three. + ## When you want a real object, not a mock A mock is right when you intend to **assert on the interaction** — what was called, with which diff --git a/website/guide/testing.md b/website/guide/testing.md index 5d32e4f..03ac3bf 100644 --- a/website/guide/testing.md +++ b/website/guide/testing.md @@ -51,7 +51,6 @@ real modules: ```shell dotnet add package DependencyModules.xUnit -dotnet add package DependencyModules.NSubstitute ``` ```csharp @@ -89,9 +88,13 @@ every test needs in one file at the assembly level: using DependencyModules.NSubstitute; [assembly: ApplicationModule] -[assembly: NSubstituteSupport] +[assembly: NSubstituteSupport] // or [MoqSupport] / [FakeItEasySupport] ``` +`NSubstituteSupport` is what enables [`[Mock]`](/guide/testing-mocks), and it comes from a separate +package — one per mocking library, so use whichever you already have. See +[choosing a mocking library](/guide/testing-mocks#choosing-a-mocking-library). + Every test in the project now gets `ApplicationModule` without saying so: ```csharp