Appearance
Are you an LLM? You can read better optimized documentation at /testing/overview.md for this page in Markdown format
Testing overview
This document provides a technical overview of the testing strategy, frameworks, and execution procedures for the TheExampleApp application. The testing approach is multi-layered, encompassing unit, integration, and end-to-end tests to ensure code quality, component correctness, and application stability.
Testing strategy
The application employs a classic testing pyramid strategy to provide comprehensive test coverage at different levels of granularity.
Unit Tests: These form the base of the pyramid and are designed to be fast and focused. They verify the logic of individual C# classes and methods (e.g., controllers, services) in complete isolation from external dependencies. Dependencies, particularly the
Contentfulclient, are mocked to ensure that tests are deterministic and only validate the component's own logic.Integration Tests: This layer tests the interaction between different components within the ASP.NET Core application pipeline. These tests are executed against an in-memory instance of the web application, allowing for HTTP requests to be made to controllers and middleware without the overhead of a full web server. This is crucial for verifying routing, model binding, filter execution, and controller-to-service interactions.
End-to-End (E2E) Tests: Situated at the top of the pyramid, E2E tests validate the entire application stack from the user's perspective. They automate a real web browser to simulate user journeys, ensuring that the server-rendered UI, client-side interactions, and backend services (including the live Contentful API) work together correctly. The project utilizes a dual-framework approach for E2E testing:
- Selenium WebDriver: C#-based tests that are part of the .NET solution, useful for validating core user flows.
- Cypress: JavaScript-based tests that offer a more modern and developer-friendly experience for complex UI testing, especially for scenarios involving different content states from the CMS.
Test project structure
The solution is organized with dedicated projects for each type of test, promoting a clean separation of concerns and allowing test suites to be run independently. This structure is defined in the TheExampleApp.sln file.
For more details on the overall solution layout, see the Project Structure documentation.
TheExampleApp.Tests: Contains all unit tests for the main web application. It references the mainTheExampleAppproject and uses a mocking library to isolate components.TheExampleApp.IntegrationTests: Contains integration tests. It leverages the ASP.NET Core test host to run the application in-memory and test the request/response pipeline.TheExampleApp.E2eTests: Contains C#-based end-to-end tests written using Selenium WebDriver./test/e2e/specs/: This directory, configured incypress.json, contains the JavaScript-based E2E tests for the Cypress test runner. Note that this is outside the .NET project structure.
Testing frameworks
The project relies on a specific set of frameworks and libraries for each testing layer. All .NET-based test projects use xUnit as the core test runner.
Unit Testing (TheExampleApp.Tests)
Unit tests are built using xUnit and the Moq library for creating mock objects.
- xUnit (
2.3.1): The primary framework for writing and running tests. - Moq (
4.7.145): A mocking library used to create test doubles for dependencies. This is essential for isolating the class under test, particularly for mocking theIContentfulClientto return predictable data without making actual API calls to Contentful.
csharp
// File: TheExampleApp.Tests/TheExampleApp.Tests.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<!-- Core SDK for testing in .NET -->
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
<!-- Mocking library for creating test doubles -->
<PackageReference Include="Moq" Version="4.7.145" />
<!-- The xUnit test framework -->
<PackageReference Include="xunit" Version="2.3.1" />
<!-- Visual Studio test runner for xUnit -->
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\TheExampleApp\TheExampleApp.csproj" />
</ItemGroup>
</Project>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
For detailed implementation, see the Unit Testing Guide.
Integration Testing (TheExampleApp.IntegrationTests)
Integration tests use xUnit and the Microsoft.AspNetCore.TestHost package to host the application in-memory.
Microsoft.AspNetCore.TestHost(2.0.1): This package provides aTestServerclass that allows the application to be hosted in-memory. Tests can then use anHttpClientto send requests to theTestServerand assert on theHttpResponseMessage, effectively testing the full ASP.NET Core pipeline.
csharp
// File: TheExampleApp.IntegrationTests/TheExampleApp.IntegrationTests.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<!-- Custom target to copy dependency files after build -->
<Target Name="CopyDepsFiles" AfterTargets="Build" Condition="'$(TargetFramework)'!=''">
<ItemGroup>
<DepsFilePaths Include="$([System.IO.Path]::ChangeExtension('%(_ResolvedProjectReferencePaths.FullPath)', '.deps.json'))" />
</ItemGroup>
<Copy SourceFiles="%(DepsFilePaths.FullPath)" DestinationFolder="$(OutputPath)" Condition="Exists('%(DepsFilePaths.FullPath)')" />
</Target>
<ItemGroup>
<!-- In-memory test server for ASP.NET Core -->
<PackageReference Include="Microsoft.AspNetCore.TestHost" Version="2.0.1" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\TheExampleApp\TheExampleApp.csproj" />
</ItemGroup>
</Project>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
For detailed implementation, see the Integration Testing Guide.
End-to-End Testing
The project employs two distinct E2E testing frameworks.
1. Selenium WebDriver (TheExampleApp.E2eTests)
This project contains E2E tests written in C# using the Selenium WebDriver library.
Selenium.WebDriver(3.7.0): The core library for browser automation.- Chrome WebDriver: The project is configured to copy the Chrome WebDriver executables (
chromedriverfor Unix/Linux/Mac andchromedriver.exefor Windows) to the output directory. This means tests are intended to run against the Google Chrome browser on multiple platforms. Developers must have Google Chrome installed, and thechromedriverversion must be compatible with the installed browser version.
csharp
// File: TheExampleApp.E2eTests/TheExampleApp.E2eTests.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.5.0" />
<!-- Selenium library for browser automation -->
<PackageReference Include="Selenium.WebDriver" Version="3.7.0" />
<PackageReference Include="xunit" Version="2.3.1" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.1" />
</ItemGroup>
<ItemGroup>
<!-- Ensures the Chrome driver is available at runtime on Unix/Linux/Mac -->
<None Update="chromedriver">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
<!-- Ensures the Chrome driver is available at runtime on Windows -->
<None Update="chromedriver.exe">
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None>
</ItemGroup>
</Project>1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2. Cypress
A separate, JavaScript-based E2E test suite is managed with Cypress. Its configuration is defined in cypress.json.
baseUrl:http://localhost:3000. This requires theTheExampleAppto be running locally on port 3000 before executing Cypress tests.integrationFolder:test/e2e/specs/. This is where all Cypress test files (*.spec.js) are located.- Environment Variables (
env): The configuration defines multiple sets of Contentful API keys and Space IDs. This is a powerful feature that allows the E2E tests to be run against different content environments, such as production, a QA space, and a space designed to test empty states.
json
// File: cypress.json
{
"baseUrl": "http://localhost:3000",
"fixturesFolder": false,
"integrationFolder": "test/e2e/specs/",
"supportFile": false,
"env": {
"CONTENTFUL_SPACE_ID": "qz0n5cdakyl9",
"CONTENTFUL_DELIVERY_TOKEN": "...",
"CONTENTFUL_PREVIEW_TOKEN": "...",
"CONTENTFUL_QA_SPACE_ID": "jnzexv31feqf",
"CONTENTFUL_QA_DELIVERY_TOKEN": "...",
"CONTENTFUL_QA_PREVIEW_TOKEN": "...",
"CONTENTFUL_QA_EMPTY_STATES_SPACE_ID": "85si70kq8sjj",
"CONTENTFUL_QA_EMPTY_STATES_DELIVERY_TOKEN": "...",
"CONTENTFUL_QA_EMPTY_STATES_PREVIEW_TOKEN": "..."
}
}1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
| Environment Variable | Purpose |
|---|---|
CONTENTFUL_SPACE_ID | Default (likely production) Contentful space. |
CONTENTFUL_QA_SPACE_ID | Contentful space dedicated to Quality Assurance testing. |
CONTENTFUL_QA_EMPTY_STATES_SPACE_ID | A special QA space to test how the UI renders with no content. |
For detailed implementation, see the E2E Testing Guide.
Running tests
Tests can be executed via the command line or through an IDE like Visual Studio.
.NET Tests (Unit, Integration, Selenium)
All .NET-based tests can be run using the dotnet test command from the root of the solution directory.
bash
# Run all tests in the solution
dotnet test
# Run tests for a specific project (e.g., unit tests)
dotnet test TheExampleApp.Tests/
# Run tests for the integration suite
dotnet test TheExampleApp.IntegrationTests/1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
Because all test projects include the xunit.runner.visualstudio package, tests will also be automatically discovered and can be run from the Test Explorer window in Visual Studio.
Cypress E2E Tests
Running Cypress tests is a separate, multi-step process that requires Node.js and npm/yarn.
Start the Application: First, ensure the
TheExampleAppweb application is running and accessible at thebaseUrldefined incypress.json.bash# Navigate to the web application project cd TheExampleApp # Run the application (it should listen on http://localhost:3000) dotnet run1
2
3
4
5Run Cypress: In a separate terminal, navigate to the root of the repository and use the Cypress CLI.
bash# Install Cypress and other dependencies if not already installed npm install # To open the interactive Cypress Test Runner UI npx cypress open # To run all tests headlessly in the terminal (ideal for CI) npx cypress run1
2
3
4
5
6
7
8