diff --git a/docs/integration/moq.rst b/docs/integration/moq.rst index 864605e..4aecae2 100644 --- a/docs/integration/moq.rst +++ b/docs/integration/moq.rst @@ -89,9 +89,7 @@ You can configure the automatic mocks and/or assert calls on them as you would n Configuring Specific Dependencies ================================= -You can configure the ``AutoMock`` to provide a specific instance for a given service type (or apply any other registration behavior), -by using the ``beforeBuild`` callback argument to ``GetLoose``, ``GetStrict`` or ``GetFromRepository``, in a similar manner -to configuring a new Lifetime Scope: +You can configure the ``AutoMock`` to provide a specific instance for a given service type (or apply any other registration behavior), by using the ``beforeBuild`` callback argument to ``GetLoose``, ``GetStrict`` or ``GetFromRepository``, in a similar manner to configuring a new Lifetime Scope: .. sourcecode:: csharp @@ -111,8 +109,7 @@ to configuring a new Lifetime Scope: } } -The ``cfg`` argument passed to your callback is a regular Autofac ``ContainerBuilder`` instance, so you can -do any of the registration behavior you're used to in a normal set up. +The ``cfg`` argument passed to your callback is a regular Autofac ``ContainerBuilder`` instance, so you can do any of the registration behavior you're used to in a normal set up. You can also configure the ``AutoMock`` to use any existing mock, through the ``RegisterMock`` extension method: @@ -133,3 +130,33 @@ You can also configure the ``AutoMock`` to use any existing mock, through the `` // ...and the rest of the test } } + +Mixing Real Framework Services with Auto-Mocking +================================================ + +Be careful when adding real framework services - such as Entity Framework Core or ``Microsoft.Extensions.Logging`` - into the ``AutoMock`` container. + +``AutoMock`` automatically supplies a mock for any service it cannot otherwise resolve. That includes the individual elements of an otherwise-empty collection dependency. For example, a framework that depends on ``IEnumerable`` would normally receive an *empty* collection when no providers are registered. Under ``AutoMock``, the empty collection instead gets a single mock element injected into it. + +A loosely-mocked element returns ``null`` from any member that hasn't been explicitly set up. When a framework consumes that collection and assumes the members return non-null values, this can surface as a confusing failure deep inside the framework's own code - frequently a ``NullReferenceException`` that has nothing obviously to do with your test. + +A common example is constructing an Entity Framework Core ``DbContext`` inside an ``AutoMock`` container that also has logging wired up. EF Core asks for the registered logger providers, receives the mock element whose ``CreateLogger`` returns ``null``, and then throws when it tries to use that logger. + +.. note:: + + You may see this behavior appear intermittently - for instance, only when tests run in a particular order. That is usually because the framework caches internal state (EF Core, for example, caches an internal service provider), which can mask the problem when a "good" code path runs first. The underlying cause is the same regardless of ordering. + +If you need real framework services in your test, register concrete implementations for the services that framework consumes so ``AutoMock`` does not fill those slots with mocks. For example, provide a real logger factory (``NullLoggerFactory`` lives in the ``Microsoft.Extensions.Logging.Abstractions`` namespace): + +.. sourcecode:: csharp + + using Microsoft.Extensions.Logging.Abstractions; + + using (var mock = AutoMock.GetLoose(cfg => + cfg.RegisterInstance(NullLoggerFactory.Instance).As())) + { + // Real logging is used instead of a mock, so frameworks that consume + // the logger providers behave as they would outside of AutoMock. + } + +Alternatively, avoid mixing real framework wiring into the auto-mocking container - keep the auto-mock container focused on the system under test and its direct dependencies.