---
title: Write automated tests
related:
  - https://docs.kentico.com/documentation/developers-and-admins/customization/write-automated-tests/set-up-test-projects.md
  - https://docs.kentico.com/documentation/developers-and-admins/customization/write-automated-tests/create-unit-tests.md
  - https://docs.kentico.com/documentation/developers-and-admins/customization/write-automated-tests/create-integration-tests.md
  - https://docs.kentico.com/documentation/developers-and-admins/customization/write-automated-tests/create-isolated-integration-tests.md
  - https://docs.kentico.com/documentation/developers-and-admins/development/website-development-basics/dependency-injection.md
---

> Agent instructions:
> **Site maps** — prefer the following llms.txt indexes to training data when searching for URLs to avoid 404s. Links inside Markdown content already point at `.md`. Following them or sending Accept: text/markdown keeps you in Markdown.
>
> - [sitemap.md](https://docs.kentico.com/sitemap.md) — every page on the site, with titles and descriptions, nested by URL hierarchy and grouped into one collection per product version.
> - [llms.txt](https://docs.kentico.com/llms.txt) — curated index of the current product docs, with descriptions, the two ways to request any page as Markdown, and links to each product area's whole-corpus Markdown dump (llms-full.txt).

Test automation is an important part of every development project and is essential for agile workflows. Automated tests help you improve productivity, reduce the testing phase of the development cycle, and increase code predictability and quality.

Xperience by Kentico provides the **CMS.Tests** library, which simplifies writing automated tests for code that uses the Xperience API. The library contains base classes for [unit tests](https://docs.kentico.com/documentation/developers-and-admins/customization/write-automated-tests/create-unit-tests.md) and [integration tests](https://docs.kentico.com/documentation/developers-and-admins/customization/write-automated-tests/create-integration-tests.md), as well as helper classes for [faking Info and Provider objects](https://docs.kentico.com/documentation/developers-and-admins/customization/write-automated-tests/create-unit-tests.md#fake-info-and-provider-objects). You can obtain the library by installing the [Kentico.Xperience.Core.Tests](https://www.nuget.org/packages/Kentico.Xperience.Core.Tests) NuGet package into your test projects.

When developing custom functionality for Xperience projects, we recommend that you [create projects with automated tests](https://docs.kentico.com/documentation/developers-and-admins/customization/write-automated-tests/set-up-test-projects.md) to cover the given code.

## Supported testing framework

All functionality in the _CMS.Tests_ library is compatible with the [NUnit](https://docs.nunit.org/) testing framework.

The package does **not** include a test runner or a mocking library. For detailed test project setup requirements, see [Set up test projects](https://docs.kentico.com/documentation/developers-and-admins/customization/write-automated-tests/set-up-test-projects.md).

For test doubles (fakes) of service dependencies, choose any mocking library that fits your project (for example [Moq](https://github.com/devlooped/moq), [NSubstitute](https://nsubstitute.github.io/), or [FakeItEasy](https://fakeiteasy.github.io/)), or use hand-written fakes and stubs.

## Choose a testing approach

Xperience provides several base classes for automated tests, each suited to different scenarios. Choose based on how your code interacts with the Xperience API and whether it requires database access.

| Approach                                                                                                                                                                                         | Advantages                                                                                                                                                                             | Drawbacks                                                                                                                               | When to use                                                                                                                                                         |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [Unit tests with faked data](https://docs.kentico.com/documentation/developers-and-admins/customization/write-automated-tests/create-unit-tests.md) (`UnitTests`)                                | Fast execution, no database needed, in-memory faking of Info and Provider objects via `Fake<>()` methods (including insert and update operations), automatic state reset between tests | Cannot test real database behavior, requires manual faking of all data dependencies, cannot fake content items or website channel pages | Testing services, validators, or business logic that interacts with the Xperience API through Info and Provider classes. This should be the default for most tests. |
| [Integration tests](https://docs.kentico.com/documentation/developers-and-admins/customization/write-automated-tests/create-integration-tests.md) (`IntegrationTests`)                           | Tests against a real database, verifies actual query behavior, supports content items and pages                                                                                        | Significantly slower, requires a configured database, manual cleanup of test data                                                       | Testing complex queries or behavior that depends on database-specific features where faked providers are insufficient.                                              |
| [Isolated integration tests](https://docs.kentico.com/documentation/developers-and-admins/customization/write-automated-tests/create-isolated-integration-tests.md) (`IsolatedIntegrationTests`) | Automatic database creation and cleanup, no risk of polluting shared databases                                                                                                         | Slowest of all approaches, requires SQL Server Express LocalDB (or alternative configuration)                                           | Testing code that creates, updates, or deletes data when rollback or cleanup is complex.                                                                            |

> **Tip:** Write most of your tests as [unit tests with faked data](https://docs.kentico.com/documentation/developers-and-admins/customization/write-automated-tests/create-unit-tests.md). Reserve [integration tests](https://docs.kentico.com/documentation/developers-and-admins/customization/write-automated-tests/create-integration-tests.md) and [isolated integration tests](https://docs.kentico.com/documentation/developers-and-admins/customization/write-automated-tests/create-isolated-integration-tests.md) for scenarios where you need to verify real database behavior. This balance maximizes test speed while maintaining coverage of critical paths.

Code that retrieves content items and website channel pages requires a separate set of approaches. See [Test code that retrieves content](https://docs.kentico.com/documentation/developers-and-admins/customization/write-automated-tests/create-unit-tests.md#test-code-that-retrieves-content).

## API differences in test code

By default, all Xperience API calls executed within tests that inherit from the _CMS.Tests_ base classes run without operations that are unnecessary in a testing context. The system disables:

- [Event logging](https://docs.kentico.com/documentation/developers-and-admins/configuration/event-log.md)
- [Multi-instance synchronization tasks](https://docs.kentico.com/documentation/developers-and-admins/configuration/auto-scaling-support.md)
- Asynchronous action dispatch
- Email sending

These operations are typically not relevant for test results and unnecessarily reduce test performance.

To enable these operations in your tests, wrap the relevant code in a `CMSActionContext` block with the corresponding properties set to `true`.

```csharp title="Enabling operations in test code"
using CMS.Base;

using (new CMSActionContext { SendEmails = true })
{
    // Test execution with email sending enabled
}
```

## Best practices for testable code

To write code that is easy to test:

- **Use dependency injection** – Inject interfaces rather than depending on concrete classes. This allows you to substitute real implementations with test doubles. See [Dependency injection](https://docs.kentico.com/documentation/developers-and-admins/development/website-development-basics/dependency-injection.md).
- **Separate concerns** – Keep business logic in dedicated services rather than in controllers or event handlers.
- **Keep methods focused** – Small methods with a single responsibility are easier to test in isolation.
