C# and .NET examples · Testing and logging
Test ILogger with FakeLogger and MSTest in C#
A .NET 8 solution demonstrating how to unit test logging in C# with FakeLogger<T> from the Microsoft.Extensions.Diagnostics.Testing package. It shows how to assert on log messages and log levels written through ILogger<T> — without a mocking library, custom test doubles, or capturing console output.
In this guide: Get started · Walk through the example · Understand the details · Check the limits
🔎 Overview
The project shows how to verify logging behaviour in tests without mocking or capturing log output manually. FakeLogger<T> records all log calls and exposes them through LatestRecord, making it straightforward to assert on log messages and log levels.
✨ Features
Projects
| Project | Description |
|---|---|
Fake.Data |
Contains the Calculate class with a Divide method that logs results and errors |
Fake.Test |
MSTest project with two tests validating the logging behaviour of Calculate |
🚀 Quick start
Build and Test
cd Fake
dotnet build
dotnet test
📦 Prerequisites and installation
Requirements
NuGet Packages
Fake.Data
| Package | Version |
|---|---|
Microsoft.Extensions.Logging |
8.0.0 |
Microsoft.Extensions.Logging.Abstractions |
8.0.1 |
Microsoft.Extensions.Logging.Console |
8.0.0 |
Fake.Test
| Package | Version |
|---|---|
Microsoft.Extensions.Diagnostics.Testing |
8.5.0 |
Microsoft.NET.Test.Sdk |
17.9.0 |
MSTest.TestAdapter |
3.3.1 |
MSTest.TestFramework |
3.3.1 |
coverlet.collector |
6.0.2 |
💡 Usage
The Class Under Test
Calculate.Divide(int dividend, int divisor) performs integer division and uses ILogger<Program> to:
- Log the inputs and result on success
- Log an
Error-level entry with the exception on divide-by-zero
public int? Divide(int dividend, int divisor)
Returns null if division fails (e.g. division by zero).
🏗️ Architecture
Project Structure
Fake/
├── Fake.Data/
│ ├── Calculate.cs # Class under test — Divide method with ILogger
│ └── Fake.Data.csproj
├── Fake.Test/
│ ├── CalculateTest.cs # Two MSTest tests using FakeLogger<T>
│ └── Fake.Test.csproj
└── Fake.sln
Fake.Data also contains a small console Program.cs that runs the calculator with a console logger, so you can see the same log messages outside the tests.
🧪 Development and testing
Tests
| Test | What It Verifies |
|---|---|
CanDevide |
After Divide(10, 2), the latest log message contains "Dividing answer 5" |
CanLogError |
After Divide(10, 0), the latest log record has LogLevel.Error |
Run dotnet test Fake/Fake.sln from the repository root to execute the two committed MSTest checks. This documentation review inspected those tests; it did not execute them.
🛠️ Troubleshooting and limitations
FAQ
Why use FakeLogger<T> instead of mocking ILogger?
ILogger.Log is a generic method that is awkward to verify with mocking libraries. FakeLogger<T> is a real ILogger<T> implementation that records every entry, so tests can read LatestRecord and assert on the message, level, and exception directly.
Does FakeLogger work with xUnit or NUnit?
Yes. It comes from the Microsoft.Extensions.Diagnostics.Testing package and does not depend on a test framework; this demo happens to use MSTest.
The tests assert the latest message or log level, not complete logging history or every calculator result. Divide performs integer division and catches exceptions, returning null on failure. No performance benchmark is included.
🔗 Related documentation
Related Examples
- Nilog — typed
ILoggerextensions - Capturing all exceptions from Task.WhenAll
- Back to all C# and .NET code examples
Documentation links
Read all C# and .NET Code Examples guides online · Project overview · All developer projects