diff --git a/reviewboard/licensing/tests/providers.py b/reviewboard/licensing/tests/providers.py
new file mode 100644
index 0000000000000000000000000000000000000000..08ab2ddec4168298052ae9cfaa7f5ce400dc2098
--- /dev/null
+++ b/reviewboard/licensing/tests/providers.py
@@ -0,0 +1,317 @@
+"""License providers common to unit tests.
+
+Version Added:
+    7.1
+"""
+
+from __future__ import annotations
+
+from datetime import timedelta
+from typing import TYPE_CHECKING
+
+from django.utils import timezone
+
+from reviewboard.licensing.errors import LicenseActionError
+from reviewboard.licensing.license import LicenseInfo, LicenseStatus
+from reviewboard.licensing.license_checks import (
+    ProcessCheckLicenseResult,
+    ProcessCheckLicenseResultStatus,
+)
+from reviewboard.licensing.provider import BaseLicenseProvider
+
+if TYPE_CHECKING:
+    from collections.abc import Sequence
+
+    from django.http import HttpRequest
+    from djblets.util.typing import JSONValue
+
+    from reviewboard.licensing.license_checks import RequestCheckLicenseResult
+    from reviewboard.licensing.provider import LicenseAction
+
+
+class BasicTestsLicenseProvider(BaseLicenseProvider):
+    """Sample license provider used for unit tests.
+
+    This provides the following licenses:
+
+    * ``license1``
+
+      Unlicensed, expiring in 100 days.
+
+      Includes line items.
+
+    * ``license2``
+
+      Licensed, expiring in 5 days.
+
+      Includes a plan ID and name.
+
+    Version Added:
+        7.1
+    """
+
+    license_provider_id = 'basic-tests-provider'
+
+    custom_actions = {
+        'test',
+    }
+
+    def get_license_actions(
+        self,
+        *,
+        license_info: LicenseInfo,
+        request: (HttpRequest | None) = None,
+    ) -> Sequence[LicenseAction]:
+        """Return actions to display when viewing a license.
+
+        This will return a custom "test" action.
+
+        Args:
+            license_info (reviewboard.licensing.license.LicenseInfo):
+                The license information that will be displayed.
+
+            request (django.http.HttpRequest, optional):
+                The HTTP request from the client.
+
+        Returns:
+            list of LicenseAction:
+            The list of actions to display for the license.
+        """
+        return [{
+            'action_id': 'test',
+            'label': 'Test',
+            'url': f'https://example.com/{license_info.license_id}/',
+        }]
+
+    def get_licenses(self) -> Sequence[LicenseInfo]:
+        """Return the list of available licenses.
+
+        Returns:
+            list of reviewboard.licensing.license.LicenseInfo:
+            The list of licenses provided.
+        """
+        license1 = self.get_license_by_id('license1')
+        license2 = self.get_license_by_id('license2')
+
+        assert license1
+        assert license2
+
+        return [license1, license2]
+
+    def get_license_by_id(
+        self,
+        license_id: str,
+    ) -> LicenseInfo | None:
+        """Return a license with the given provider-unique ID.
+
+        Args:
+            license_id (str):
+                The provider-unique ID for the license.
+
+        Returns:
+            reviewboard.licensing.license.LicenseInfo:
+            The license information, or ``None`` if not found.
+        """
+        if license_id == 'license1':
+            return LicenseInfo(
+                expires=timezone.now() + timedelta(days=100),
+                license_id=license_id,
+                licensed_to='Test User',
+                line_items=[
+                    'Line 1',
+                    'Line 2',
+                ],
+                product_name='Test Product',
+                status=LicenseStatus.UNLICENSED)
+        elif license_id == 'license2':
+            return LicenseInfo(
+                expires=timezone.now() + timedelta(days=5),
+                license_id=license_id,
+                licensed_to='Test User',
+                plan_id='plan1',
+                plan_name='Plan 1',
+                product_name='Test Product',
+                status=LicenseStatus.LICENSED)
+        else:
+            return None
+
+    def get_manage_license_url(
+        self,
+        *,
+        license_info: LicenseInfo,
+    ) -> str | None:
+        """Return the URL for managing licenses online.
+
+        Args:
+            license_info (reviewboard.licensing.license.LicenseInfo):
+                The license information to link to in the portal.
+
+        Returns:
+            str:
+            The URL to the license portal, or ``None`` if one is not
+            available.
+        """
+        if license_info.license_id == 'license1':
+            return f'https://example.com/{license_info.license_id}/'
+
+        return None
+
+    def get_check_license_status_url(
+        self,
+        *,
+        license_info: LicenseInfo,
+    ) -> str | None:
+        """Return data used to check a license for validity.
+
+        Args:
+            license_info (reviewboard.licensing.license.LicenseInfo):
+                The license information that will be checked.
+
+            request (django.http.HttpRequest, optional):
+                The HTTP request from the client, if any.
+
+        Returns:
+            reviewboard.licensing.license_checks.RequestCheckLicenseResult:
+            The state used to control the license check, or ``None`` if checks
+            are not supported.
+
+        Raises:
+            reviewboard.licensing.errors.LicenseActionError:
+                There was an error generating data for this request.
+        """
+        return f'https://example.com/{license_info.license_id}/check/'
+
+    def get_check_license_request(
+        self,
+        *,
+        license_info: LicenseInfo,
+        request: (HttpRequest | None) = None,
+    ) -> RequestCheckLicenseResult | None:
+        return {
+            'data': {
+                'license_id': license_info.license_id,
+                'something': 'special',
+                'version': '1.0',
+            },
+            'url': f'https://example.com/{license_info.license_id}/check/'
+        }
+
+    def process_check_license_result(
+        self,
+        *,
+        license_info: LicenseInfo,
+        check_request_data: JSONValue,
+        check_response_data: JSONValue,
+        request: (HttpRequest | None) = None,
+    ) -> ProcessCheckLicenseResult:
+        """Return data used to check a license for validity.
+
+        Args:
+            license_info (reviewboard.licensing.license.LicenseInfo):
+                The license information that will be checked.
+
+            request (django.http.HttpRequest, optional):
+                The HTTP request from the client, if any.
+
+        Returns:
+            reviewboard.licensing.license_checks.RequestCheckLicenseResult:
+            The state used to control the license check, or ``None`` if checks
+            are not supported.
+
+        Raises:
+            reviewboard.licensing.errors.LicenseActionError:
+                There was an error generating data for this request.
+        """
+        assert isinstance(check_response_data, dict)
+
+        if check_response_data.get('version') != '1.0':
+            raise LicenseActionError(
+                'Invalid version from the licensing server! Oh no!'
+            )
+
+        status: ProcessCheckLicenseResultStatus
+
+        if check_response_data.get('updated'):
+            status = ProcessCheckLicenseResultStatus.APPLIED
+            license_info.expires = timezone.now() + timedelta(days=365)
+            license_info.plan_id = 'smpbpe1'
+            license_info.plan_name = 'Super Mega Power Bundle Pro Enterprise'
+        elif check_response_data.get('latest'):
+            status = ProcessCheckLicenseResultStatus.HAS_LATEST
+        else:
+            status = ProcessCheckLicenseResultStatus.ERROR_APPLYING
+
+        return {
+            'license_infos': {
+                'license1': self.get_js_license_model_data(
+                    license_info=license_info),
+            },
+            'status': status,
+        }
+
+
+class ExpiredTestsLicenseProvider(BaseLicenseProvider):
+    """Sample license provider used for expiration unit tests.
+
+    This provides the following licenses:
+
+    * ``license1``
+
+      Hard-expired 50 days ago.
+
+    * ``license2``
+
+      Expired, in grace period as of 2 days ago.
+
+    Version Added:
+        7.1
+    """
+
+    license_provider_id = 'expired-tests-provider'
+
+    def get_licenses(self) -> Sequence[LicenseInfo]:
+        """Return the list of available licenses.
+
+        Returns:
+            list of reviewboard.licensing.license.LicenseInfo:
+            The list of licenses provided.
+        """
+        license1 = self.get_license_by_id('license1')
+        license2 = self.get_license_by_id('license2')
+
+        assert license1
+        assert license2
+
+        return [license1, license2]
+
+    def get_license_by_id(
+        self,
+        license_id: str,
+    ) -> LicenseInfo | None:
+        """Return a license with the given provider-unique ID.
+
+        Args:
+            license_id (str):
+                The provider-unique ID for the license.
+
+        Returns:
+            reviewboard.licensing.license.LicenseInfo:
+            The license information, or ``None`` if not found.
+        """
+        if license_id == 'license1':
+            return LicenseInfo(
+                expires=timezone.now() - timedelta(days=50),
+                is_trial=True,
+                license_id=license_id,
+                licensed_to='Test User',
+                product_name='Test Product',
+                status=LicenseStatus.HARD_EXPIRED)
+        elif license_id == 'license2':
+            return LicenseInfo(
+                expires=timezone.now() - timedelta(days=2),
+                license_id=license_id,
+                licensed_to='Test User',
+                product_name='Test Product',
+                status=LicenseStatus.EXPIRED_GRACE_PERIOD)
+        else:
+            return None
diff --git a/reviewboard/licensing/tests/test_licenses_view.py b/reviewboard/licensing/tests/test_licenses_view.py
index 2c2b833cd2799ac1fb301aeaa5a802c5932ee2c3..4c514c2dbd53a7f9611df3b06033514a2f427416 100644
--- a/reviewboard/licensing/tests/test_licenses_view.py
+++ b/reviewboard/licensing/tests/test_licenses_view.py
@@ -7,194 +7,21 @@ Version Added:
 from __future__ import annotations
 
 import json
-from datetime import datetime, timedelta, timezone as tz
-from typing import TYPE_CHECKING
+from datetime import datetime, timezone as tz
 from uuid import uuid4
 
 import kgb
 from django.urls import reverse
 from django.utils import timezone
 
-from reviewboard.licensing.errors import LicenseActionError
-from reviewboard.licensing.license import LicenseInfo, LicenseStatus
-from reviewboard.licensing.license_checks import (
-    ProcessCheckLicenseResult,
-    ProcessCheckLicenseResultStatus,
-)
 from reviewboard.licensing.provider import BaseLicenseProvider
-from reviewboard.licensing.registry import (LicenseProviderRegistry,
-                                            license_provider_registry)
+from reviewboard.licensing.registry import license_provider_registry
+from reviewboard.licensing.tests.providers import (
+    BasicTestsLicenseProvider,
+    ExpiredTestsLicenseProvider,
+)
 from reviewboard.testing import TestCase
 
-if TYPE_CHECKING:
-    from collections.abc import Iterable, Sequence
-
-    from django.http import HttpRequest
-    from djblets.util.typing import JSONValue
-
-    from reviewboard.licensing.license_checks import RequestCheckLicenseResult
-    from reviewboard.licensing.provider import LicenseAction
-
-
-class _MyLicenseProvider1(BaseLicenseProvider):
-    license_provider_id = 'my-provider-1'
-
-    def get_license_actions(
-        self,
-        *,
-        license_info: LicenseInfo,
-        request: (HttpRequest | None) = None,
-    ) -> Sequence[LicenseAction]:
-        return [{
-            'action_id': 'test',
-            'label': 'Test',
-            'url': f'https://example.com/{license_info.license_id}/',
-        }]
-
-    def get_licenses(self) -> Sequence[LicenseInfo]:
-        license1 = self.get_license_by_id('license1')
-        license2 = self.get_license_by_id('license2')
-
-        assert license1
-        assert license2
-
-        return [license1, license2]
-
-    def get_license_by_id(
-        self,
-        license_id: str,
-    ) -> LicenseInfo | None:
-        if license_id == 'license1':
-            return LicenseInfo(
-                expires=timezone.now() + timedelta(days=100),
-                license_id=license_id,
-                licensed_to='Test User',
-                line_items=[
-                    'Line 1',
-                    'Line 2',
-                ],
-                product_name='Test Product',
-                status=LicenseStatus.UNLICENSED)
-        elif license_id == 'license2':
-            return LicenseInfo(
-                expires=timezone.now() + timedelta(days=5),
-                license_id=license_id,
-                licensed_to='Test User',
-                plan_id='plan1',
-                plan_name='Plan 1',
-                product_name='Test Product',
-                status=LicenseStatus.LICENSED)
-        else:
-            return None
-
-    def get_manage_license_url(
-        self,
-        *,
-        license_info: LicenseInfo,
-    ) -> str | None:
-        if license_info.license_id == 'license1':
-            return f'https://example.com/{license_info.license_id}/'
-
-        return None
-
-    def get_check_license_status_url(
-        self,
-        *,
-        license_info: LicenseInfo,
-    ) -> str | None:
-        return f'https://example.com/{license_info.license_id}/check/'
-
-    def get_check_license_request(
-        self,
-        *,
-        license_info: LicenseInfo,
-        request: (HttpRequest | None) = None,
-    ) -> RequestCheckLicenseResult | None:
-        return {
-            'data': {
-                'license_id': license_info.license_id,
-                'something': 'special',
-                'version': '1.0',
-            },
-            'url': f'https://example.com/{license_info.license_id}/check/'
-        }
-
-    def process_check_license_result(
-        self,
-        *,
-        license_info: LicenseInfo,
-        check_request_data: JSONValue,
-        check_response_data: JSONValue,
-        request: (HttpRequest | None) = None,
-    ) -> ProcessCheckLicenseResult:
-        assert isinstance(check_response_data, dict)
-
-        if check_response_data.get('version') != '1.0':
-            raise LicenseActionError(
-                'Invalid version from the licensing server! Oh no!'
-            )
-
-        status: ProcessCheckLicenseResultStatus
-
-        if check_response_data.get('updated'):
-            status = ProcessCheckLicenseResultStatus.APPLIED
-            license_info.expires = timezone.now() + timedelta(days=365)
-            license_info.plan_id = 'smpbpe1'
-            license_info.plan_name = 'Super Mega Power Bundle Pro Enterprise'
-        elif check_response_data.get('latest'):
-            status = ProcessCheckLicenseResultStatus.HAS_LATEST
-        else:
-            status = ProcessCheckLicenseResultStatus.ERROR_APPLYING
-
-        return {
-            'status': status,
-            'license_infos': {
-                'license1': self.get_js_license_model_data(
-                    license_info=license_info),
-            },
-        }
-
-
-class _MyLicenseProvider2(BaseLicenseProvider):
-    license_provider_id = 'my-provider-2'
-
-    def get_licenses(self) -> Sequence[LicenseInfo]:
-        license1 = self.get_license_by_id('license1')
-        license2 = self.get_license_by_id('license2')
-
-        assert license1
-        assert license2
-
-        return [license1, license2]
-
-    def get_license_by_id(
-        self,
-        license_id: str,
-    ) -> LicenseInfo | None:
-        if license_id == 'license1':
-            return LicenseInfo(
-                expires=timezone.now() - timedelta(days=50),
-                is_trial=True,
-                license_id=license_id,
-                licensed_to='Test User',
-                product_name='Test Product',
-                status=LicenseStatus.HARD_EXPIRED)
-        elif license_id == 'license2':
-            return LicenseInfo(
-                expires=timezone.now() - timedelta(days=2),
-                license_id=license_id,
-                licensed_to='Test User',
-                product_name='Test Product',
-                status=LicenseStatus.EXPIRED_GRACE_PERIOD)
-        else:
-            return None
-
-
-class _MyLicenseProviderRegistry(LicenseProviderRegistry):
-    def get_defaults(self) -> Iterable[BaseLicenseProvider]:
-        yield _MyLicenseProvider1()
-        yield _MyLicenseProvider2()
-
 
 class LicenseViewTests(kgb.SpyAgency, TestCase):
     """Unit tests for LicenseView.
@@ -225,8 +52,8 @@ class LicenseViewTests(kgb.SpyAgency, TestCase):
         super().setUpClass()
 
         license_providers = [
-            _MyLicenseProvider1(),
-            _MyLicenseProvider2(),
+            BasicTestsLicenseProvider(),
+            ExpiredTestsLicenseProvider(),
         ]
 
         cls._license_providers = license_providers
@@ -292,7 +119,7 @@ class LicenseViewTests(kgb.SpyAgency, TestCase):
                 'license_infos': [
                     {
                         'attrs': {
-                            'actionTarget': 'my-provider-1:license1',
+                            'actionTarget': 'basic-tests-provider:license1',
                             'actions': [
                                 {
                                     'actionID': 'test',
@@ -325,7 +152,7 @@ class LicenseViewTests(kgb.SpyAgency, TestCase):
                     },
                     {
                         'attrs': {
-                            'actionTarget': 'my-provider-1:license2',
+                            'actionTarget': 'basic-tests-provider:license2',
                             'actions': [
                                 {
                                     'actionID': 'test',
@@ -361,7 +188,7 @@ class LicenseViewTests(kgb.SpyAgency, TestCase):
                 'license_infos': [
                     {
                         'attrs': {
-                            'actionTarget': 'my-provider-2:license1',
+                            'actionTarget': 'expired-tests-provider:license1',
                             'actions': [],
                             'canUploadLicense': False,
                             'expiresDate': datetime(2025, 3, 2, 0, 0,
@@ -387,7 +214,7 @@ class LicenseViewTests(kgb.SpyAgency, TestCase):
                     },
                     {
                         'attrs': {
-                            'actionTarget': 'my-provider-2:license2',
+                            'actionTarget': 'expired-tests-provider:license2',
                             'actions': [],
                             'canUploadLicense': False,
                             'expiresDate': datetime(2025, 4, 19, 0, 0,
@@ -483,7 +310,7 @@ class LicenseViewTests(kgb.SpyAgency, TestCase):
 
         response = client.post(reverse('admin-licenses'), {
             'action': 'xxx',
-            'action_target': 'my-provider-2:xxx',
+            'action_target': 'expired-tests-provider:xxx',
         })
 
         self.assertEqual(response.status_code, 400)
@@ -498,7 +325,7 @@ class LicenseViewTests(kgb.SpyAgency, TestCase):
 
         response = client.post(reverse('admin-licenses'), {
             'action': 'xxx',
-            'action_target': 'my-provider-2:license1',
+            'action_target': 'expired-tests-provider:license1',
         })
 
         self.assertEqual(response.status_code, 400)
@@ -514,7 +341,7 @@ class LicenseViewTests(kgb.SpyAgency, TestCase):
 
         response = client.post(reverse('admin-licenses'), {
             'action': 'license-update-check',
-            'action_target': 'my-provider-1:license1',
+            'action_target': 'basic-tests-provider:license1',
         })
 
         self.assertEqual(response.status_code, 200)
@@ -539,7 +366,7 @@ class LicenseViewTests(kgb.SpyAgency, TestCase):
 
         response = client.post(reverse('admin-licenses'), {
             'action': 'license-update-check',
-            'action_target': 'my-provider-2:license1',
+            'action_target': 'expired-tests-provider:license1',
         })
 
         self.assertEqual(response.status_code, 200)
@@ -559,7 +386,7 @@ class LicenseViewTests(kgb.SpyAgency, TestCase):
 
         response = client.post(reverse('admin-licenses'), {
             'action': 'process-license-update',
-            'action_target': 'my-provider-1:license2',
+            'action_target': 'basic-tests-provider:license2',
             'check_request_data': json.dumps({
                 'license_id': 'license1',
                 'something': 'special',
@@ -576,7 +403,7 @@ class LicenseViewTests(kgb.SpyAgency, TestCase):
             'status': 'applied',
             'license_infos': {
                 'license1': {
-                    'actionTarget': 'my-provider-1:license2',
+                    'actionTarget': 'basic-tests-provider:license2',
                     'actions': [
                         {
                             'actionID': 'test',
@@ -619,7 +446,7 @@ class LicenseViewTests(kgb.SpyAgency, TestCase):
 
         response = client.post(reverse('admin-licenses'), {
             'action': 'process-license-update',
-            'action_target': 'my-provider-1:license2',
+            'action_target': 'basic-tests-provider:license2',
             'check_request_data': json.dumps({
                 'license_id': 'license1',
                 'something': 'special',
@@ -636,7 +463,7 @@ class LicenseViewTests(kgb.SpyAgency, TestCase):
             'status': 'has-latest',
             'license_infos': {
                 'license1': {
-                    'actionTarget': 'my-provider-1:license2',
+                    'actionTarget': 'basic-tests-provider:license2',
                     'actions': [
                         {
                             'actionID': 'test',
@@ -676,7 +503,7 @@ class LicenseViewTests(kgb.SpyAgency, TestCase):
 
         response = client.post(reverse('admin-licenses'), {
             'action': 'process-license-update',
-            'action_target': 'my-provider-1:license2',
+            'action_target': 'basic-tests-provider:license2',
             'check_request_data': json.dumps({
                 'license_id': 'license1',
                 'something': 'special',
@@ -708,7 +535,7 @@ class LicenseViewTests(kgb.SpyAgency, TestCase):
 
         response = client.post(reverse('admin-licenses'), {
             'action': 'process-license-update',
-            'action_target': 'my-provider-1:license2',
+            'action_target': 'basic-tests-provider:license2',
         })
 
         self.assertEqual(response.status_code, 400)
@@ -733,7 +560,7 @@ class LicenseViewTests(kgb.SpyAgency, TestCase):
 
         response = client.post(reverse('admin-licenses'), {
             'action': 'process-license-update',
-            'action_target': 'my-provider-1:license2',
+            'action_target': 'basic-tests-provider:license2',
             'check_request_data': '"abc123"',
         })
 
@@ -759,7 +586,7 @@ class LicenseViewTests(kgb.SpyAgency, TestCase):
 
         response = client.post(reverse('admin-licenses'), {
             'action': 'process-license-update',
-            'action_target': 'my-provider-1:license2',
+            'action_target': 'basic-tests-provider:license2',
             'check_request_data': 'xxx',
             'check_response_data': '"def456"',
         })
@@ -788,7 +615,7 @@ class LicenseViewTests(kgb.SpyAgency, TestCase):
 
         response = client.post(reverse('admin-licenses'), {
             'action': 'process-license-update',
-            'action_target': 'my-provider-1:license2',
+            'action_target': 'basic-tests-provider:license2',
             'check_request_data': '"abc123"',
             'check_response_data': 'xxx',
         })
