Test Frameworks
xUnit, NUnit, and MSTest are the three major .NET test frameworks. xUnit is the recommended framework for new projects.Framework Comparison
- xUnit
- NUnit
- MSTest
[Fact]for single test[Theory]with[InlineData]for parameterized- Each test runs in new class instance (enforces isolation)
- Best parallelism support
Assertions
Assertions verify that actual values match expected outcomes. FluentAssertions provides expressive, readable assertion syntax.Assertion Libraries
- Assert.Equal(expected, actual) - Built-in xUnit assertions
- FluentAssertions -
actual.Should().Be(expected) - Collection assertions -
Should().HaveCount(),Contain(),BeEquivalentTo() - Exception assertions -
action.Should().Throw<T>() - Async assertions -
await act.Should().ThrowAsync<T>() - BeEquivalentTo - Compares object graphs recursively
Use BeEquivalentTo for object graph comparison instead of multiple individual property assertions — cleaner and catches new properties automatically.
Test Driven Development
TDD writes a failing test first, then minimum code to pass, then refactors. It drives design through test specifications.TDD Cycle
- Red - Write a failing test for the next small behavior
- Green - Write the minimum code to pass
- Refactor - Clean up while keeping green
TDD Principles
- Write the test before the implementation code
- Each test covers one behavior, not one method
- BDD (Behavior-Driven Development) uses Given/When/Then naming
- FIRST principles: Fast, Independent, Repeatable, Self-verifying, Timely
- Mutation testing (Stryker.NET) validates test effectiveness
- Code coverage is a lower bound — 80% line coverage is a minimum, not goal
Mocking
Mocking frameworks (NSubstitute, Moq, FakeItEasy) create test doubles that simulate dependency behavior.Mocking Frameworks
NSubstitute
Clean syntax, implicit interface matching
Moq
Popular, mature, Setup/Verify pattern
FakeItEasy
Natural syntax with A.Fake<T>
Mocking Best Practices
- Stubs - Return values; Mocks also verify calls
- Mock at the boundary (interfaces injected by DI)
- Verify only meaningful interactions, not every call
- Use
Arg.Any<T>()for arguments you don’t care about - Prefer fakes over mocks for complex stateful collaborators
Prefer NSubstitute over Moq for new projects — its implicit interface matching syntax is cleaner and requires fewer characters per setup.
Code Coverage
Code coverage measures which lines, branches, and paths are exercised by tests. Coverlet + ReportGenerator are the standard .NET coverage tools.Coverage Metrics
- Line coverage - Measures statements executed
- Branch coverage - Measures conditions (more valuable)
- Method coverage - Measures methods called
- Path coverage - Measures execution paths (comprehensive but expensive)
Coverage Tools
dotnet test --collect:"XPlat Code Coverage"- Coverlet.Collector - NuGet package for test project
- ReportGenerator - Converts coverage XML to HTML reports
- Cobertura XML - Integrates with Azure DevOps and GitHub Actions
[ExcludeFromCodeCoverage]- Exclude generated code
Containerization
Docker containers package .NET applications with their dependencies for consistent deployment across environments.Docker Best Practices
Multi-stage Build
Use SDK image to build, ASP.NET runtime image to run (smaller, secure images)
Non-root User
USER app prevents privilege escalationHealth Checks
HEALTHCHECK CMD curl --fail http://localhost/health.dockerignore
Exclude bin/obj/secrets from build context
Container Features
- Multi-stage builds - Minimize image size
- Base images:
mcr.microsoft.com/dotnet/aspnet:<version> dotnet publish -p:PublishProfile=DefaultContainerpushes OCI image directly- Pin base image versions in production
Azure Deployment
Azure App Service, AKS, Container Apps, and Azure Functions are the primary .NET hosting targets in Azure.Azure Services
- App Service
- AKS
- Container Apps
- PaaS host for web apps and APIs
- Deployment slots for zero-downtime
- Scale up/out based on SKU
- Integrated with App Insights
Azure Best Practices
- Managed Identity - Eliminates connection string credentials
- Key Vault - Store secrets, reference from App Settings
- Application Insights - Distributed telemetry and monitoring
- Deployment slots - Blue-green deployments with slot swap
Web Deploy
Web Deploy (MSDeploy) syncs web application content to IIS and Azure App Service.Deployment Options
- dotnet publish output to folder, then msdeploy sync
- Azure Zip Deploy - POST to
https://<app>.scm.azurewebsites.net/api/zipdeploy - Deployment slots - Enable blue-green with warm swap
- Kudu SCM - Console for file system access and debugging
- GitHub Actions -
azure/webapps-deployaction
Always deploy to a staging slot first and use slot swap for production — this enables instant rollback and warms up the new version before it serves traffic.
Configuration Management
ASP.NET Core configuration is a layered key-value system. Providers include JSON files, environment variables, Azure Key Vault, and user secrets.Configuration Providers
Provider order (later providers override earlier ones):appsettings.jsonappsettings.{env}.json- Environment variables
- User secrets (development)
- Command line arguments
Configuration Features
- Environment variables - Use double underscore
__as hierarchy separator - User Secrets -
dotnet user-secretsfor local development - IOptionsMonitor<T> - Reloads config at runtime without restart
- ValidateDataAnnotations - Validates options with data annotations
- AddAzureKeyVault - Integrates Key Vault as configuration provider
Configuration Best Practices
ValidateOnStart
Fail-fast on missing config
IOptionsMonitor
For settings that change without restarts
User Secrets
Locally; Key Vault in production