Skip to content

Repository files navigation

πŸ“š Library System Testing

A production-grade .NET solution demonstrating comprehensive test coverage and QA best practices β€” unit testing, integration testing, architecture enforcement, and load testing β€” across a layered Library Management API.


.NET xUnit Build Coverage


πŸ“‚ Project Structure

LibrarySystem/
β”‚
β”œβ”€β”€ πŸ“ src/
β”‚   β”œβ”€β”€ LibrarySystem.API/              # ASP.NET Core Web API (Minimal API + Controllers)
β”‚   β”‚   β”œβ”€β”€ Controllers/                 #   LoansController, MembersController
β”‚   β”‚   β”œβ”€β”€ Program.cs                   #   App entry point, DI, Minimal API endpoints
β”‚   β”‚   └── LibrarySystem.API.csproj
β”‚   β”‚
β”‚   β”œβ”€β”€ LibrarySystem.Data/             # Data Access Layer (EF Core)
β”‚   β”‚   β”œβ”€β”€ Entities/                    #   Book, Member, Loan
β”‚   β”‚   β”œβ”€β”€ LibraryDbContext.cs          #   EF Core DbContext with Fluent API config
β”‚   β”‚   └── LibrarySystem.Data.csproj
β”‚   β”‚
β”‚   └── LibrarySystem.Services/         # Business Logic Layer
β”‚       β”œβ”€β”€ Interfaces/                  #   IBookService, ILoanService, IMemberService
β”‚       β”œβ”€β”€ BookService.cs
β”‚       β”œβ”€β”€ LoanService.cs
β”‚       β”œβ”€β”€ MemberService.cs
β”‚       └── LibrarySystem.Services.csproj
β”‚
β”œβ”€β”€ πŸ“ tests/
β”‚   β”œβ”€β”€ LibrarySystem.UnitTests/        # βœ… Unit Tests
β”‚   β”œβ”€β”€ LibrarySystem.IntegrationTests/ # βœ… Integration Tests
β”‚   β”œβ”€β”€ LibrarySystem.ArchitectureTests/# βœ… Architecture Tests
β”‚   └── LibrarySystem.LoadTests/        # βœ… Load / Performance Tests
β”‚
└── LibrarySystem.slnx                  # Solution file

πŸ§ͺ Testing Types & Strategies

1. Unit Testing

Isolated tests validating individual service methods against an EF Core InMemory database, ensuring business logic correctness without any external dependencies.

Aspect Detail
Project LibrarySystem.UnitTests
Framework xUnit
Assertions Shouldly β€” fluent, readable assertion library
Mocking Moq β€” available for interface mocking
Database EF Core InMemory Provider β€” unique Guid database per test for full isolation
Coverage Coverlet β€” code coverage collection
Test Count 17 tests across 3 test classes

Test Classes:

  • BookServiceUnitTests β€” GetAll, GetById, GetById_NotFound
  • LoanServiceUnitTests β€” Borrow/Return flows, expired membership, max loans, no stock, outstanding fines, overdue fines, double return
  • MemberServiceUnitTests β€” Registration, duplicate email detection

2. Integration Testing

End-to-end HTTP pipeline tests using WebApplicationFactory<T> to spin up an in-memory test server, exercising the full request pipeline β€” routing, middleware, DI, and database β€” without a running server.

Aspect Detail
Project LibrarySystem.IntegrationTests
Framework xUnit + IClassFixture<WebApplicationFactory<Program>>
Assertions Shouldly
Test Server Microsoft.AspNetCore.Mvc.Testing (WebApplicationFactory)
Database EF Core InMemory β€” seeded per test via DI scope
Coverage Coverlet
Test Count 10 tests across 3 test classes

Test Classes:

  • BookEndpointsIntegrationTests β€” GET /api/books, GET /api/books/{id} (OK + NotFound)
  • LoanEndpointsIntegrationTests β€” POST /api/loans (Borrow), PUT /api/loans/{id}/return (Return), NotFound, BadRequest (out-of-stock, already returned)
  • MemberEndpointsIntegrationTests β€” POST /api/members (Register), BadRequest (duplicate email)

3. Architecture Testing

Automated enforcement of structural rules and dependency boundaries using reflection-based analysis, preventing architectural erosion over time.

Aspect Detail
Project LibrarySystem.ArchitectureTests
Framework xUnit
Assertions Shouldly
Rule Engine NetArchTest.Rules β€” fluent API for .NET architecture constraints
Coverage Coverlet
Test Count 6 tests

Enforced Rules:

# Rule Purpose
1 Data layer β†’ ⊘ Services, API Domain layer must not depend on higher layers
2 Services layer β†’ ⊘ API Services must not depend on the presentation layer
3 Interfaces start with "I" Naming convention enforcement
4 Service classes end with "Service" Naming convention enforcement
5 Controllers end with "Controller" Naming convention enforcement
6 Controllers inherit ControllerBase Structural inheritance verification

4. Load / Performance Testing

HTTP-based load testing against a running instance of the API to validate throughput, latency, and stability under sustained concurrent traffic.

Aspect Detail
Project LibrarySystem.LoadTests
Framework NBomber + NBomber.Http
Execution Standalone console application (dotnet run)
Scenario book_catalog_load_test β€” sustained load on GET /api/books
Load Profile 50 concurrent connections for 30 seconds with a 5-second warmup

⚠️ Note: The API must be running locally on http://localhost:5280 before executing load tests.


πŸ”’ Test Isolation & Infrastructure

All automated tests (Unit, Integration, Architecture) achieve complete isolation without Docker or external services:

Mechanism Used By Description
EF Core InMemory Database Unit Tests Each test creates a fresh Guid-named in-memory database, ensuring zero cross-test contamination.
WebApplicationFactory<Program> Integration Tests Creates an in-memory HTTP test server with a replaced DbContext. Each test explicitly calls EnsureDeleted() + EnsureCreated() for a clean slate.
NetArchTest Reflection Architecture Tests Pure reflection-based assembly scanning β€” no state or infrastructure required.
Standalone Process Load Tests Executes against a live API instance. No test containers β€” the API is expected to be running externally.

No Docker Compose, Testcontainers, or external broker configurations are required to run the automated test suite.


πŸš€ How to Run the Tests

Prerequisites


Run the Entire Test Suite

Execute all Unit, Integration, and Architecture tests across the entire solution:

dotnet test

Run a Specific Test Project

Target a single test project by name:

# Unit Tests only
dotnet test LibrarySystem.UnitTests

# Integration Tests only
dotnet test LibrarySystem.IntegrationTests

# Architecture Tests only
dotnet test LibrarySystem.ArchitectureTests

Run Tests by Filter (Trait or Name)

Use --filter to execute specific tests:

# Run a single test by display name
dotnet test --filter "BorrowBookAsync_ShouldSucceedAndDecrementStock_WhenAllRulesPass"

# Run all tests in a specific class
dotnet test --filter "FullyQualifiedName~LoanServiceUnitTests"

# Run all Architecture tests
dotnet test --filter "FullyQualifiedName~ArchitectureTests"

Generate & View Code Coverage Report

Generate a coverage report using Coverlet and visualize it with ReportGenerator:

# Step 1: Install ReportGenerator global tool (one-time)
dotnet tool install -g dotnet-reportgenerator-globaltool

# Step 2: Run tests with coverage collection (Cobertura format)
dotnet test --collect:"XPlat Code Coverage" --results-directory ./TestResults

# Step 3: Generate the HTML report
reportgenerator -reports:./TestResults/**/coverage.cobertura.xml -targetdir:./CoverageReport

# Step 4: Open the report
# Windows:
start ./CoverageReport/index.html
# macOS:
open ./CoverageReport/index.html
# Linux:
xdg-open ./CoverageReport/index.html

Run Load Tests

Step 1: Start the API first:

dotnet run --project LibrarySystem.API

Step 2: In a separate terminal, run the load test:

dotnet run --project LibrarySystem.LoadTests

Reports are generated in LibrarySystem.LoadTests/bin/Debug/net10.0/reports/.


πŸ› οΈ Key Libraries & Frameworks

Category Library Version Purpose
Test Framework xUnit 2.9.3 Test runner and discovery
Assertions Shouldly 4.3.0 Fluent, expressive assertions
Mocking Moq 4.20.72 Interface/class mocking
In-Memory DB EF Core InMemory 10.0.8 Database isolation for tests
Architecture Rules NetArchTest.Rules 1.3.2 Assembly-level constraint testing
Load Testing NBomber 6.4.1 HTTP load & performance testing
Code Coverage Coverlet 10.0.1 Coverage data collection
Test Server Mvc.Testing 10.0.8 WebApplicationFactory for integration tests

πŸ“ Architecture Overview

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚                LibrarySystem.API                 β”‚
β”‚         (Minimal API + Controllers)              β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚              LibrarySystem.Services              β”‚
β”‚    (BookService / LoanService / MemberService)   β”‚
β”œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€
β”‚               LibrarySystem.Data                 β”‚
β”‚       (LibraryDbContext / EF Core Entities)      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

Dependency Direction:  API β†’ Services β†’ Data

Architecture tests enforce this dependency direction at build time, preventing any layer from referencing a layer above it.


πŸ“„ License

This project is licensed under the MIT License. Feel free to fork, adapt, and use it as a reference for testing strategies in your own .NET projects.


Built with ❀️ by Ahmed Anwer.

About

A comprehensive .NET 10 testing showcase demonstrating Unit, Integration, Architecture (NetArchTest), and Load testing (NBomber) on a layered Library Management API.

Topics

Resources

Stars

Watchers

Forks

Contributors

Languages