diff --git a/.changes/unreleased/Features-20240903-132428.yaml b/.changes/unreleased/Features-20240903-132428.yaml new file mode 100644 index 00000000000..08df6958990 --- /dev/null +++ b/.changes/unreleased/Features-20240903-132428.yaml @@ -0,0 +1,6 @@ +kind: Features +body: Enable `--resource-type` and `--exclude-resource-type` CLI flags and environment variables for `dbt test` +time: 2024-09-03T13:24:28.592837+01:00 +custom: + Author: TowardOliver dbeatty10 + Issue: "10656" diff --git a/core/dbt/cli/main.py b/core/dbt/cli/main.py index e042888ef4b..ca79d5eb073 100644 --- a/core/dbt/cli/main.py +++ b/core/dbt/cli/main.py @@ -785,6 +785,8 @@ def freshness(ctx, **kwargs): @click.pass_context @global_flags @p.exclude +@p.resource_type +@p.exclude_resource_type @p.profiles_dir @p.project_dir @p.select diff --git a/core/dbt/node_types.py b/core/dbt/node_types.py index 52503f46ba2..71ef90594a2 100644 --- a/core/dbt/node_types.py +++ b/core/dbt/node_types.py @@ -26,6 +26,11 @@ NodeType.Snapshot, ] +TEST_NODE_TYPES: List["NodeType"] = [ + NodeType.Test, + NodeType.Unit, +] + VERSIONED_NODE_TYPES: List["NodeType"] = [ NodeType.Model, ] diff --git a/core/dbt/task/test.py b/core/dbt/task/test.py index d1958d4ef4b..356328a4263 100644 --- a/core/dbt/task/test.py +++ b/core/dbt/task/test.py @@ -3,7 +3,17 @@ import re import threading from dataclasses import dataclass -from typing import TYPE_CHECKING, Any, Dict, List, Optional, Tuple, Type, Union +from typing import ( + TYPE_CHECKING, + Any, + Collection, + Dict, + List, + Optional, + Tuple, + Type, + Union, +) import daff @@ -25,9 +35,9 @@ from dbt.exceptions import BooleanError, DbtInternalError from dbt.flags import get_flags from dbt.graph import ResourceTypeSelector -from dbt.node_types import NodeType +from dbt.node_types import TEST_NODE_TYPES, NodeType from dbt.parser.unit_tests import UnitTestManifestLoader -from dbt.task.base import BaseRunner +from dbt.task.base import BaseRunner, resource_types_from_args from dbt.utils import _coerce_decimal, strtobool from dbt_common.dataclass_schema import dbtClassMixin from dbt_common.events.format import pluralize @@ -387,6 +397,16 @@ class TestTask(RunTask): def raise_on_first_error(self) -> bool: return False + @property + def resource_types(self) -> List[NodeType]: + resource_types: Collection[NodeType] = resource_types_from_args( + self.args, set(TEST_NODE_TYPES), set(TEST_NODE_TYPES) + ) + + # filter out any non-test node types + resource_types = [rt for rt in resource_types if rt in TEST_NODE_TYPES] + return list(resource_types) + def get_node_selector(self) -> ResourceTypeSelector: if self.manifest is None or self.graph is None: raise DbtInternalError("manifest and graph must be set to get perform node selection") @@ -394,7 +414,7 @@ def get_node_selector(self) -> ResourceTypeSelector: graph=self.graph, manifest=self.manifest, previous_state=self.previous_state, - resource_types=[NodeType.Test, NodeType.Unit], + resource_types=self.resource_types, ) def get_runner_type(self, _) -> Optional[Type[BaseRunner]]: diff --git a/tests/functional/unit_testing/test_unit_testing.py b/tests/functional/unit_testing/test_unit_testing.py index 7332ddccb64..53cfc84f4bf 100644 --- a/tests/functional/unit_testing/test_unit_testing.py +++ b/tests/functional/unit_testing/test_unit_testing.py @@ -76,11 +76,19 @@ def test_basic(self, project): ) assert len(results) == 1 - # Exclude unit tests with environment variable + # Exclude unit tests with environment variable for build command os.environ["DBT_EXCLUDE_RESOURCE_TYPES"] = "unit_test" results = run_dbt(["build", "--select", "my_model"], expect_pass=True) assert len(results) == 1 + # Exclude unit tests with environment variable for test command + results = run_dbt(["test", "--select", "my_model"], expect_pass=True) + assert len(results) == 0 + + # Exclude unit tests with environment variable for list command + results = run_dbt(["list", "--select", "my_model"], expect_pass=True) + assert len(results) == 1 + del os.environ["DBT_EXCLUDE_RESOURCE_TYPES"] # Test select by test name diff --git a/tests/functional/unit_testing/test_ut_resource_types.py b/tests/functional/unit_testing/test_ut_resource_types.py index 85d198bb60a..09f64bdd061 100644 --- a/tests/functional/unit_testing/test_ut_resource_types.py +++ b/tests/functional/unit_testing/test_ut_resource_types.py @@ -46,6 +46,12 @@ def test_unit_test_list(self, project): results = run_dbt(["list", "--exclude-resource-types", "model", "test"]) assert sorted(results) == EXPECTED_UNIT_TESTS + results = run_dbt(["test", "--resource-type", "unit_test"]) + assert len(results) == len(EXPECTED_UNIT_TESTS) + + results = run_dbt(["test", "--exclude-resource-types", "model", "test"]) + assert len(results) == len(EXPECTED_UNIT_TESTS) + # data tests results = run_dbt(["list", "--resource-type", "test"]) assert sorted(results) == EXPECTED_DATA_TESTS @@ -53,6 +59,12 @@ def test_unit_test_list(self, project): results = run_dbt(["list", "--exclude-resource-types", "unit_test", "model"]) assert sorted(results) == EXPECTED_DATA_TESTS + results = run_dbt(["test", "--resource-type", "test"]) + assert len(results) == len(EXPECTED_DATA_TESTS) + + results = run_dbt(["test", "--exclude-resource-types", "unit_test", "model"]) + assert len(results) == len(EXPECTED_DATA_TESTS) + results = run_dbt(["build", "--resource-type", "test"]) assert len(results) == len(EXPECTED_DATA_TESTS) @@ -61,11 +73,17 @@ def test_unit_test_list(self, project): # models results = run_dbt(["list", "--resource-type", "model"]) - assert len(results) == len(EXPECTED_MODELS) + assert sorted(results) == EXPECTED_MODELS results = run_dbt(["list", "--exclude-resource-type", "unit_test", "test"]) assert sorted(results) == EXPECTED_MODELS + results = run_dbt(["test", "--resource-type", "model"]) + assert len(results) == 0 + + results = run_dbt(["test", "--exclude-resource-types", "unit_test", "test"]) + assert len(results) == 0 + results = run_dbt(["build", "--resource-type", "model"]) assert len(results) == len(EXPECTED_MODELS)