Use ServiceCollection in Unit Tests with .NET
A popular unit test — and also a necessary test — is the correct registration of interfaces and their implementation with dependency…
Use ServiceCollection in Unit Tests with .NET

A popular unit test — and also a necessary test — is the correct registration of interfaces and their implementation with dependency injection. And a common mistake is that the associated IServiceCollection interface is used for mocks that lead to faulty tests.
The problem
Given the following code, in which an interface and an implementation are registered in a .NET application.
using Microsoft.Extensions.DependencyInjection;
using System;
public interface IMyService
{
void DoSomething();
}
public class MyService : IMyService
{
public void DoSomething()
{
Console.WriteLine("Doing something...");
}
}
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
// Registering the singleton
services.AddSingleton<IMyService, MyService>();
}
}
An obvious test would be to check that AddSingleton of the interface is called.
public class StartupTests
{
[Fact]
public void ConfigureServices_ShouldRegisterIMyServiceAsSingleton()
{
// Arrange
IServiceCollection services = Substitute.For<IServiceCollection>();
Startup startup = new Startup();
// Act
startup.ConfigureServices(services);
// Assert
services.Received().AddSingleton<IMyService, MyService>();
}
}
The problem is that AddSingleton is a simple extension method that itself cannot be easily mocked and thus used for mocked tests.
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// Microsoft.Extensions.DependencyInjection.Abstractions.dll
public static IServiceCollection AddSingleton<TService, [DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicConstructors)] TImplementation>(this IServiceCollection services)
where TService : class
where TImplementation : class, TService
{
ThrowHelper.ThrowIfNull(services);
return services.AddSingleton(typeof(TService), typeof(TImplementation));
}
A corresponding test fails with the following error message:
Message: NSubstitute.Exceptions.ReceivedCallsException : Expected to receive a call matching: Add(ServiceType: IMyService Lifetime: Singleton ImplementationType: MyService) Actually received no matching calls. Received 1 non-matching call (non-matching arguments indicated with ‘’ characters): Add( ServiceType: IMyService Lifetime: Singleton ImplementationType: MyService)*
Use of ServiceCollection
The generally recommended solution in the community is not to use the interface IServiceCollection for testing, but the implementation ServiceCollection.
// Arrange
ServiceCollection services = new ServiceCollection();
Startup startup = new Startup();
// Act
startup.ConfigureServices(services);
// Assert
ServiceDescriptor? serviceDescriptor = services
.Where(
serviceDescriptor => serviceDescriptor.ServiceType == typeof(IMyService)
&& serviceDescriptor.ImplementationType == typeof(MyService)
&& serviceDescriptor.Lifetime == ServiceLifetime.Singleton)
.SingleOrDefault();
Assert.NotNull(serviceDescriptor);
The enormous advantage is that I am not testing a mock, but the real implementation of ServiceCollection, which is also used at runtime. Furthermore, asserting ServiceCollection in more complex tests is much easier.
To make it even easier, you can build simple test extensions to reduce the test effort per test:
public static class ServiceCollectionTests
{
public static void VerifyAddSingleton<TService, TImplementation>(
this ServiceCollection collection, int times = 1)
where TImplementation : class, TService
{
VerifyAdd<TService, TImplementation>(collection, ServiceLifetime.Singleton, times);
}
public static void VerifyAdd<TService, TImplementation>(
this ServiceCollection collection, ServiceLifetime lifetime, int times)
where TImplementation : class, TService
{
Type serviceType = typeof(TService);
Type implementationType = typeof(TImplementation);
List<ServiceDescriptor> items = collection
.Where(
serviceDescriptor => serviceDescriptor.ServiceType == typeof(TService)
&& serviceDescriptor.ImplementationType == typeof(TImplementation)
&& serviceDescriptor.Lifetime == lifetime)
.ToList();
Assert.Equal(times, items.Count);
}
}
The test looks correspondingly slimmer:
// Arrange
ServiceCollection services = new ServiceCollection();
Startup startup = new Startup();
// Act
startup.ConfigureServices(services);
// Assert
services.VerifyAddSingleton<IMyService, MyService>();
Using NSubstitute
A potential further solution with NSubstitute is to mock the base method Add and check whether it has been called with the appropriate parameters.
// Arrange
IServiceCollection services = Substitute.For<IServiceCollection>();
Startup startup = new Startup();
// Act
startup.ConfigureServices(services);
// Assert
services.Received().Add(Arg.Is<ServiceDescriptor>(descriptor =>
descriptor.ServiceType == typeof(IMyService) &&
descriptor.ImplementationType == typeof(MyService) &&
descriptor.Lifetime == ServiceLifetime.Singleton));
Conclusion
Simpler and better quality tests can be achieved when verifying dependency injection with ServiceCollection.
Autor

medialesson.com/contact

Contact me here.
BEN ABT
Ben is a passionate developer and software architect and especially focused on .NET, cloud and IoT. In his professional he works on high-scalable platforms for IoT and Industry 4.0 focused on the next generation of connected industry based on Azure and .NET. He runs the largest german-speaking C# forum myCSharp.de, is the founder of the Azure UserGroup Stuttgart, a co-organizer of the AzureSaturday, runs his blog, participates in open source projects, speaks at various conferences and user groups and also has a bit free time. He is a Microsoft MVP since 2015 for .NET and Azure.
Originally published at https://schwabencode.com on October 10, 2024.
메타데이터
- post_id
- b42c62ed20f7
- slug
- use-servicecollection-in-unit-tests-with-net-b42c62ed20f7
- url
- https://medium.com/medialesson/use-servicecollection-in-unit-tests-with-net-b42c62ed20f7
- canonical_url
- https://medium.com/medialesson/use-servicecollection-in-unit-tests-with-net-b42c62ed20f7
- author_url
- https://medium.com/@benjaminabt
- status
- ok
- fetched_at
- 2026-07-14 13:18:53