Skip to content

# `nautobot.apps.testing`

Utilities for apps to implement test automation.

## `nautobot.apps.testing.APITestCase`

Bases: `ModelTestCase`

Base test case for API requests.

api_version: Specific API version to test. Leave unset to test the default behavior. Override with set_api_version()

### `assert_no_verboten_content(response)`

Check an API response for content that should not be exposed in the API.

If a specific API has a false failure here (maybe it has security-related strings as model flags or something?), its test case should overload self.VERBOTEN_STRINGS appropriately.

### `get_m2m_fields()`

Get serializer field names that are many-to-many or one-to-many and thus affected by ?exclude_m2m=true.

### `setUp()`

Create a token for API calls.

### `set_api_version(api_version)`

Set or unset a specific API version for requests in this test case.

## `nautobot.apps.testing.APITransactionTestCase`

Bases: `APITransactionTestCase`, `NautobotTestCaseMixin`

### `setUp()`

Create a superuser and token for API calls.

## `nautobot.apps.testing.APIViewTestCases`

### `CreateObjectViewTestCase`

Bases: `APITestCase`

#### `test_bulk_create_objects()`

POST a set of objects in a single request.

#### `test_create_object()`

POST a single object with permission.

#### `test_create_object_without_permission()`

POST a single object without permission.

#### `test_recreate_object_csv()`

CSV export an object, delete it, and recreate it via CSV import.

### `DeleteObjectViewTestCase`

Bases: `APITestCase`

#### `get_deletable_object()`

Get an instance that can be deleted.

For some models this may just be any random object, but when we have FKs with `on_delete=models.PROTECT` (as is often the case) we need to find or create an instance that doesn't have such entanglements.

#### `get_deletable_object_pks()`

Get a list of PKs corresponding to objects that can be safely bulk-deleted.

For some models this may just be any random objects, but when we have FKs with `on_delete=models.PROTECT` (as is often the case) we need to find or create an instance that doesn't have such entanglements.

#### `test_bulk_delete_objects()`

DELETE a set of objects in a single request.

#### `test_delete_object()`

DELETE a single object identified by its primary key.

#### `test_delete_object_without_permission()`

DELETE a single object without permission.

### `GetObjectViewTestCase`

Bases: `APITestCase`

#### `test_get_object()`

GET a single object as an authenticated user with permission to view the object.

#### `test_get_object_anonymous()`

GET a single object as an unauthenticated user.

#### `test_get_object_without_permission()`

GET a single object as an authenticated user without the required permission.

#### `test_options_object()`

Make an OPTIONS request for a single object.

### `ListObjectsViewTestCase`

Bases: `APITestCase`

#### `get_depth_fields()`

Get a list of model fields that could be tested with the ?depth query parameter

#### `test_list_objects()`

GET a list of objects as an authenticated user with permission to view the objects.

#### `test_list_objects_anonymous()`

GET a list of objects as an unauthenticated user.

#### `test_list_objects_csv()`

GET a list of objects in CSV format as an authenticated user with permission to view some objects.

#### `test_list_objects_depth_0()`

GET a list of objects using the "?depth=0" parameter.

#### `test_list_objects_depth_1()`

GET a list of objects using the "?depth=1" parameter.

#### `test_list_objects_filtered()`

GET a list of objects filtered by ID.

#### `test_list_objects_unknown_filter_no_strict_filtering()`

GET a list of objects with an unknown filter parameter and no strict filtering, expect it to be ignored.

#### `test_list_objects_unknown_filter_strict_filtering()`

GET a list of objects with an unknown filter parameter and strict filtering, expect a 400 response.

#### `test_list_objects_without_permission()`

GET a list of objects as an authenticated user without the required permission.

#### `test_options_objects()`

Make an OPTIONS request for a list endpoint.

### `NotesURLViewTestCase`

Bases: `APITestCase`

Validate Notes URL on objects that have the Note model Mixin.

### `TreeModelAPIViewTestCaseMixin`

Test `?depth=2` query parameter for TreeModel

#### `test_list_objects_depth_2()`

GET a list of objects using the "?depth=2" parameter. TreeModel Only

### `UpdateObjectViewTestCase`

Bases: `APITestCase`

#### `test_bulk_update_objects()`

PATCH a set of objects in a single request.

#### `test_get_put_round_trip()`

GET and then PUT an object and verify that it's accepted and unchanged.

#### `test_options_returns_expected_choices()`

Make an OPTIONS request for a list endpoint and validate choices match expected choices for serializer.

#### `test_update_object()`

PATCH a single object identified by its ID.

#### `test_update_object_without_permission()`

PATCH a single object without permission.

## `nautobot.apps.testing.FilterTestCases`

### `BaseFilterTestCase`

Bases: `TestCase`

Base class for testing of FilterSets.

#### `get_filterset_test_values(field_name, queryset=None)`

Returns a list of distinct values from the requested queryset field to use in filterset tests.

Returns a list for use in testing multiple choice filters. The size of the returned list is random but will contain at minimum 2 unique values. The list of values will match at least 2 instances when passed to the queryset's filter(field_name__in=[]) method but will fail to match at least one instance.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`field_name` | `str` | The name of the field to retrieve test values from. | required
`queryset` | `QuerySet` | The queryset to retrieve test values. Defaults to `self.queryset`. | `None`

Returns:

Type | Description
--- | ---
`list` | A list of unique values derived from the queryset.

Raises:

Type | Description
--- | ---
`ValueError` | Raised if unable to find a combination of 2 or more unique values to filter the queryset to a subset of the total instances.

### `FilterTestCase`

Bases: `BaseFilterTestCase`

Add common tests for all FilterSets.

#### `get_q_filter()`

Helper method to return q filter.

#### `test_automagic_filters()`

https://github.com/nautobot/nautobot/issues/6656

#### `test_boolean_filters_generic()`

Test all `RelatedMembershipBooleanFilter` filters found in `self.filterset.filters` except for the ones with custom filter logic defined in its `method` attribute.

This test asserts that `filter=True` matches `self.queryset.filter(field__isnull=False)` and that `filter=False` matches `self.queryset.filter(field__isnull=True)`.

#### `test_filters_generic()`

Test all multiple choice filters declared in `self.generic_filter_tests`.

This test uses `get_filterset_test_values()` to retrieve a valid set of test data and asserts that the filterset filter output matches the corresponding queryset filter. The majority of Nautobot filters use conjoined=False, so the extra logic to support conjoined=True has not been implemented here. TagFilter and similar "AND" filters are not supported.

Examples:

Multiple tests can be performed for the same filter by adding multiple entries in `generic_filter_tests` with explicit field names. For example, to test a NaturalKeyOrPKMultipleChoiceFilter, use: generic_filter_tests = ( ["filter_name", "field_name__name"], ["filter_name", "field_name__id"], )

If a field name is not declared, the filter name will be used for the field name: generic_filter_tests = ( ["devices"], ) This expects a field named `devices` on the model and a filter named `devices` on the filterset.

#### `test_id()`

Verify that the filterset supports filtering by id with only lookup `__n`.

#### `test_invalid_filter()`

Verify that the filterset reports as invalid when initialized with an unsupported filter parameter.

#### `test_no_distinct_on_empty_filter_params()`

Verify that an empty filterset doesn't cause a `SELECT DISTINCT`.

#### `test_q_filter_valid()`

Test the `q` filter based on attributes in `filter_predicates`.

#### `test_tags_filter()`

Test the `tags` filter which should be present on all PrimaryModel filtersets.

### `NameOnlyFilterTestCase`

Bases: `FilterTestCase`

Add simple tests for filtering by name.

### `NameSlugFilterTestCase`

Bases: `FilterTestCase`

Add simple tests for filtering by name and by slug.

### `TenancyFilterTestCaseMixin`

Bases: `TestCase`

Add test cases for tenant and tenant-group filters.

## `nautobot.apps.testing.FormTestCases`

### `BaseFormTestCase`

Bases: `TestCase`

Base class for generic form tests.

## `nautobot.apps.testing.ModelTestCase`

Bases: `TestCase`

Parent class for TestCases which deal with models.

## `nautobot.apps.testing.ModelTestCases`

### `BaseModelTestCase`

Bases: `NautobotTestCaseMixin`, `TestCase`

Base class for generic model tests.

#### `test_composite_key()`

Check that `composite_key` and filtering by `composite_key` both work.

#### `test_dynamic_group_api()`

For dynamic-group capable models, check that they work as intended.

#### `test_get_docs_url()`

Check that `get_docs_url()` returns a valid static file path for this model.

#### `test_natural_key_symmetry()`

Check that `natural_key()` and `get_by_natural_key()` work reciprocally.

## `nautobot.apps.testing.ModelViewTestCase`

Bases: `ModelTestCase`

Base TestCase for model views. Subclass to test individual views.

### `reverse_url_attribute = None` `class-attribute` `instance-attribute`

Name of instance field to pass as a kwarg when looking up URLs for creating/editing/deleting a model instance.

If unspecified, "pk" and "slug" will be tried, in that order.

## `nautobot.apps.testing.NautobotDataMigrationTest`

Bases: `TestCase`

### `populateDataBeforeMigration(installed_apps)`

Populate your Nautobot data before migrating from the first migration to the second

## `nautobot.apps.testing.NautobotTestCaseMixin`

Base class for all Nautobot-specific unit tests.

### `absolute_api_url(obj)`

Get the absolute API URL ("http://nautobot.example.com/api/...") for a given object.

### `add_permissions(*names, **kwargs)`

Assign a set of permissions to the test user. Accepts permission names in the form ._. Additional keyword arguments will be passed to the ObjectPermission constructor to allow creating more detailed permissions.

Examples:

    >>> add_permissions("ipam.add_vlangroup", "ipam.view_vlangroup")
    >>> add_permissions("ipam.add_vlangroup", "ipam.view_vlangroup", constraints={"pk": "uuid-1234"})

### `assertApproximateNumQueries(minimum, maximum, func=None, *args, using=DEFAULT_DB_ALIAS, **kwargs)`

Like assertNumQueries, but fuzzier. Assert that the number of queries falls within an acceptable range.

### `assertBodyContains(response, text, count=None, status_code=200, msg_prefix='', html=False)`

Like Django's `assertContains`, but uses `extract_page_body` utility function to scope the check more narrowly.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`response` | `HttpResponse` | The response to inspect | required
`text` | `str` | Plaintext or HTML to check for in the response body | required
`count` | `int` | Number of times the `text` should occur, or None if we don't care as long as it's present at all. | `None`
`status_code` | `int` | HTTP status code expected | `200`
`html` | `bool` | If True, handle `text` as HTML, ignoring whitespace etc, as in Django's `assertHTMLEqual()`. | `False`

### `assertHttpStatus(response, expected_status, msg=None)`

TestCase method. Provide more detail in the event of an unexpected HTTP response.

### `assertInstanceEqual(instance, data, exclude=None, api=False)`

Compare a model instance to a dictionary, checking that its attribute values match those specified in the dictionary.

:param instance: Python object instance :param data: Dictionary of test data used to define the instance :param exclude: List of fields to exclude from comparison (e.g. passwords, which get hashed) :param api: Set to True is the data is a JSON representation of the instance

### `assertJobResultStatus(job_result, expected_status=JobResultStatusChoices.STATUS_SUCCESS)`

Assert that the given job_result has the expected_status, or print the job logs to aid in debugging.

### `assertQuerysetEqualAndNotEmpty(qs, values, *args, **kwargs)`

Wrapper for assertQuerysetEqual with additional logic to assert input queryset and values are not empty

### `create_tags(*names)` `classmethod`

Create and return a Tag instance for each name given.

DEPRECATED: use TagFactory instead.

### `model_to_dict(instance, fields, api=False)`

Return a dictionary representation of an instance.

### `prepare_instance(instance)`

Test cases can override this method to perform any necessary manipulation of an instance prior to its evaluation against test data. For example, it can be used to decrypt a Secret's plaintext attribute.

### `remove_permissions(*names, **kwargs)`

Remove a set of permissions. Accepts permission names in the form ._. Additional keyword arguments will be passed to the ObjectPermission constructor to allow creating more detailed permissions.

Examples:

    >>> remove_permissions("ipam.add_vlangroup", "ipam.view_vlangroup")
    >>> remove_permissions("ipam.add_vlangroup", "ipam.view_vlangroup", constraints={"pk": "uuid-1234"})

### `setUpNautobot(client=True, populate_status=False)`

Setup shared testuser, statuses and client.

### `tearDown()`

Clear cache after each test case.

In theory this shouldn't be necessary as our cache should appropriately update and clear itself when data changes occur, but in practice we've seen issues here. Best guess at present is that it's due to `TransactionTestCase` truncating the database, which presumably doesn't trigger the relevant Django signals that would otherwise refresh the cache appropriately.

See also: https://code.djangoproject.com/ticket/11505

## `nautobot.apps.testing.NautobotTestClient`

Bases: `APIClient`

Base client class for Nautobot testing.

DO NOT USE THIS IN PRODUCTION NAUTOBOT CODE.

### `__init__(*args, **kwargs)`

Default the SERVER_NAME to "nautobot.example.com" rather than Django's default "testserver".

This matches the ALLOWED_HOSTS set in nautobot/core/tests/nautobot_config.py and helps to protect us against issues like https://github.com/nautobot/nautobot/issues/3065.

## `nautobot.apps.testing.OpenAPISchemaTestCases`

### `BaseSchemaTestCase`

Bases: `TestCase`

Base class for testing of the OpenAPI schema.

#### `assert_component_mapped_by_object_type(schema, models)`

Test method to assert that this polymorphic component has the expected permitted types.

#### `assert_not_nullable_property(component_schema, property_name)`

Test method to assert that the given component property is marked as non-nullable.

#### `assert_not_read_only_property(component_schema, property_name)`

Test method to assert that the given component property is not marked as read-only.

#### `assert_nullable_property(component_schema, property_name)`

Test method to assert that the given component property is marked as nullable.

#### `assert_read_only_property(component_schema, property_name)`

Test method to assert that the given component property is marked as read-only.

#### `get_component_schema(component_name, api_version=None)`

Helper method to pull a specific component schema from the larger OpenAPI schema already loaded.

#### `get_property_ref_component_name(component_schema, property_name)`

Helper method to identify a component referenced by the given property of the current component.

#### `get_schema_property(component_schema, property_name)`

Helper method to pull a specific property schema from a larger component schema already extracted.

#### `validate_polymorphic_property(component_name, property_name, models=None, nullable=False, read_only=True, many=False)`

Bringing it all together.

This validates the schema to show that: - The component exists and has such a property - The property has the correct `nullable` and `readOnly` values - The property has the correct multiplicity - The property is a reference to another component - The property's referenced component is polymorphic and has the expected set of model content-types.

Returns:

Type | Description
--- | ---
`Tuple[ref_component_name, ref_component_schema]` | The referenced component's name and schema.

## `nautobot.apps.testing.SeleniumTestCase`

Bases: `StaticLiveServerTestCase`, `NautobotTestCaseMixin`

Base test case for Splinter Selenium integration testing with custom helper methods.

This extends `django.contrib.staticfiles.testing.StaticLiveServerTestCase` so there is no need to run `collectstatic` prior to running tests.

### `click_edit_form_create_button()`

Helper function to click the "Create" button on a form.

### `click_list_view_add_button()`

Helper function to click the "Add" button on a list view.

### `click_navbar_entry(parent_menu_name, child_menu_name)`

Helper function to click on a parent menu and child menu in the navigation bar.

### `fill_filters_select2_field(field_name, value)`

Helper function to fill a Select2 single selection field on filters modals.

### `fill_select2_field(field_name, value)`

Helper function to fill a Select2 single selection field on add/edit forms.

### `fill_select2_multiselect_field(field_name, value)`

Helper function to fill a Select2 multi-selection field.

### `login(username, password, login_url=LOGIN_URL, button_text='Log In')`

Navigate to `login_url` and perform a login w/ the provided `username` and `password`.

### `tearDownClass()` `classmethod`

Close down the browser after tests are ran.

## `nautobot.apps.testing.TestCase`

Bases: `NautobotTestCaseMixin`, `TestCase`

Base class for all Nautobot-specific unit tests.

### `setUp()`

Initialize user and client.

## `nautobot.apps.testing.TransactionTestCase`

Bases: `NautobotTestCaseMixin`, `TransactionTestCase`

Base test case class using the TransactionTestCase for unit testing

### `setUp()`

Provide a clean, post-migration state before each test case.

django.test.TransactionTestCase truncates the database after each test runs. We need at least the default statuses present in the database in order to run tests.

## `nautobot.apps.testing.ViewTestCases`

We keep any TestCases with test_* methods inside a class to prevent unittest from trying to run them.

### `BulkDeleteObjectsViewTestCase`

Bases: `ModelViewTestCase`

Delete multiple instances.

#### `get_deletable_object_pks()`

Get a list of PKs corresponding to objects that can be safely bulk-deleted.

For some models this may just be any random objects, but when we have FKs with `on_delete=models.PROTECT` (as is often the case) we need to find or create an instance that doesn't have such entanglements.

### `BulkEditObjectsViewTestCase`

Bases: `ModelViewTestCase`

Edit multiple instances.

:bulk_edit_data: A dictionary of data to be used when bulk editing a set of objects. This data should differ from that used for initial object creation within setUpTestData().

#### `test_bulk_edit_objects_nullable_fields()`

Assert that "set null" fields on the bulk-edit form are correctly passed through to the job.

### `BulkRenameObjectsViewTestCase`

Bases: `ModelViewTestCase`

Rename multiple instances.

### `CreateMultipleObjectsViewTestCase`

Bases: `ModelViewTestCase`

Create multiple instances using a single form. Expects the creation of three new instances by default.

:bulk_create_count: The number of objects expected to be created (default: 3). :bulk_create_data: A dictionary of data to be used for bulk object creation.

### `CreateObjectViewTestCase`

Bases: `ModelViewTestCase`

Create a single new instance.

:form_data: Data to be used when creating a new object.

### `DeleteObjectViewTestCase`

Bases: `ModelViewTestCase`

Delete a single instance.

#### `get_deletable_object()`

Get an instance that can be deleted.

For some models this may just be any random object, but when we have FKs with `on_delete=models.PROTECT` (as is often the case) we need to find or create an instance that doesn't have such entanglements.

### `DeviceComponentTemplateViewTestCase`

Bases: `EditObjectViewTestCase`, `DeleteObjectViewTestCase`, `CreateMultipleObjectsViewTestCase`, `BulkEditObjectsViewTestCase`, `BulkRenameObjectsViewTestCase`, `BulkDeleteObjectsViewTestCase`

TestCase suitable for testing device component template models (ConsolePortTemplates, InterfaceTemplates, etc.)

### `DeviceComponentViewTestCase`

Bases: `GetObjectViewTestCase`, `GetObjectChangelogViewTestCase`, `GetObjectNotesViewTestCase`, `EditObjectViewTestCase`, `DeleteObjectViewTestCase`, `ListObjectsViewTestCase`, `CreateMultipleObjectsViewTestCase`, `BulkEditObjectsViewTestCase`, `BulkRenameObjectsViewTestCase`, `BulkDeleteObjectsViewTestCase`

TestCase suitable for testing device component models (ConsolePorts, Interfaces, etc.)

#### `bulk_add_data = None` `class-attribute` `instance-attribute`

Used for bulk-add (distinct from bulk-create) view testing; self.bulk_create_data will be used if unset.

#### `test_bulk_add_component()`

Test bulk-adding this component to devices/virtual-machines.

### `EditObjectViewTestCase`

Bases: `ModelViewTestCase`

Edit a single existing instance.

:update_data: Data to be used when updating the first existing object, fall back to form_data if not provided. :form_data: Fall back to this data if update_data is not provided, for backward compatibility.

### `GetObjectChangelogViewTestCase`

Bases: `ModelViewTestCase`

View the changelog for an instance.

### `GetObjectNotesViewTestCase`

Bases: `ModelViewTestCase`

View the notes for an instance.

### `GetObjectViewTestCase`

Bases: `ModelViewTestCase`

Retrieve a single instance.

### `ListObjectsViewTestCase`

Bases: `ModelViewTestCase`

Retrieve multiple instances.

#### `test_list_objects_unknown_filter_no_strict_filtering()`

Verify that without STRICT_FILTERING, an unknown filter is ignored.

#### `test_list_objects_unknown_filter_strict_filtering()`

Verify that with STRICT_FILTERING, an unknown filter results in an error message and no matches.

#### `test_list_view_app_banner()`

If example app is installed, check if the app banner is rendered correctly in ObjectListView.

#### `test_model_properties_as_table_columns_are_not_orderable()`

Check for table columns that are property-based and not orderable.

### `OrganizationalObjectViewTestCase`

Bases: `GetObjectViewTestCase`, `GetObjectChangelogViewTestCase`, `GetObjectNotesViewTestCase`, `CreateObjectViewTestCase`, `EditObjectViewTestCase`, `DeleteObjectViewTestCase`, `ListObjectsViewTestCase`, `BulkDeleteObjectsViewTestCase`

TestCase suitable for all organizational objects

### `PrimaryObjectViewTestCase`

Bases: `GetObjectViewTestCase`, `GetObjectChangelogViewTestCase`, `GetObjectNotesViewTestCase`, `CreateObjectViewTestCase`, `EditObjectViewTestCase`, `DeleteObjectViewTestCase`, `ListObjectsViewTestCase`, `BulkEditObjectsViewTestCase`, `BulkDeleteObjectsViewTestCase`

TestCase suitable for testing all standard View functions for primary objects

## `nautobot.apps.testing.create_job_result_and_run_job(module, name, source='local', *args, **kwargs)`

Test helper function to call get_job_class_and_model() then call run_job_for_testing().

## `nautobot.apps.testing.create_test_user(username='testuser', permissions=None)`

Create a User with the given permissions.

## `nautobot.apps.testing.disable_warnings(logger_name)`

Temporarily suppress expected warning messages to keep the test output clean.

## `nautobot.apps.testing.extract_form_failures(content)`

Given decoded HTML content from an HTTP response, return a list of form errors.

## `nautobot.apps.testing.extract_page_body(content)`

Given raw HTML content from an HTTP response, extract the main div only.

...
...
...

## `nautobot.apps.testing.generate_random_device_asset_tag_of_specified_size(size)`

For testing purposes only; it returns a random string of size 100 consisting of letters and numbers.

## `nautobot.apps.testing.get_deletable_objects(model, queryset)`

Returns a subset of objects in the given queryset that have no protected relationships that would prevent deletion.

## `nautobot.apps.testing.get_job_class_and_model(module, name, source='local')`

Test helper function to look up a job class and job model and ensure the latter is enabled.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`module` | `str` | Job module name | required
`name` | `str` | Job class name | required
`source` | `str` | Job grouping (default: "local") | `'local'`

Returns:

Type | Description
--- | ---
`JobClassInfo` | Named 2-tuple of (job_class, job_model)

## `nautobot.apps.testing.post_data(data)`

Take a dictionary of test data (suitable for comparison to an instance) and return a dict suitable for POSTing.

## `nautobot.apps.testing.run_job_for_testing(job, username='test-user', profile=False, **kwargs)`

Provide a common interface to run Nautobot jobs as part of unit tests.

Parameters:

Name | Type | Description | Default
--- | --- | --- | ---
`job` | `Job` | Job model instance (not Job class) to run | required
`username` | `str` | Username of existing or to-be-created User account to own the JobResult. | `'test-user'`
`profile` | `bool` | Whether to profile the job execution. | `False`

Other Parameters:

Name | Type | Description
--- | --- | ---
`**kwargs` | `any` | Input keyword arguments for Job run method.

Returns:

Type | Description
--- | ---
`JobResult` | representing the executed job