You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@airflow.apache.org by po...@apache.org on 2022/12/05 03:09:59 UTC

[airflow] branch main updated: Migrate google provider cloud utils tests from `unittests` to `pytest` (#28040)

This is an automated email from the ASF dual-hosted git repository.

potiuk pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new dd4804e05b Migrate google provider cloud utils tests from `unittests` to `pytest` (#28040)
dd4804e05b is described below

commit dd4804e05bb7e994a3782feacf47c89d2e9481f3
Author: Andrey Anshin <An...@taragol.is>
AuthorDate: Mon Dec 5 06:09:51 2022 +0300

    Migrate google provider cloud utils tests from `unittests` to `pytest` (#28040)
---
 .../_internal_client/test_secret_manager_client.py |   4 +-
 .../google/cloud/secrets/test_secret_manager.py    |  67 +++++-----
 .../cloud/utils/test_credentials_provider.py       | 137 ++++++++++-----------
 .../google/cloud/utils/test_field_sanitizer.py     |   3 +-
 .../google/cloud/utils/test_field_validator.py     |   4 +-
 .../cloud/utils/test_mlengine_operator_utils.py    |   3 +-
 .../utils/test_mlengine_prediction_summary.py      |   5 +-
 7 files changed, 103 insertions(+), 120 deletions(-)

diff --git a/tests/providers/google/cloud/_internal_client/test_secret_manager_client.py b/tests/providers/google/cloud/_internal_client/test_secret_manager_client.py
index 57a6f1fecd..2094766cb7 100644
--- a/tests/providers/google/cloud/_internal_client/test_secret_manager_client.py
+++ b/tests/providers/google/cloud/_internal_client/test_secret_manager_client.py
@@ -16,7 +16,7 @@
 # under the License.
 from __future__ import annotations
 
-from unittest import TestCase, mock
+from unittest import mock
 
 from google.api_core.exceptions import NotFound, PermissionDenied
 from google.cloud.secretmanager_v1.types import AccessSecretVersionResponse
@@ -28,7 +28,7 @@ INTERNAL_CLIENT_MODULE = "airflow.providers.google.cloud._internal_client.secret
 INTERNAL_COMMON_MODULE = "airflow.providers.google.common.consts"
 
 
-class TestSecretManagerClient(TestCase):
+class TestSecretManagerClient:
     @mock.patch(INTERNAL_CLIENT_MODULE + ".SecretManagerServiceClient")
     def test_auth(self, mock_secrets_client):
         mock_secrets_client.return_value = mock.MagicMock()
diff --git a/tests/providers/google/cloud/secrets/test_secret_manager.py b/tests/providers/google/cloud/secrets/test_secret_manager.py
index 710a575078..9636d69308 100644
--- a/tests/providers/google/cloud/secrets/test_secret_manager.py
+++ b/tests/providers/google/cloud/secrets/test_secret_manager.py
@@ -16,13 +16,13 @@
 # under the License.
 from __future__ import annotations
 
+import logging
 import re
-from unittest import TestCase, mock
+from unittest import mock
 
 import pytest
 from google.api_core.exceptions import NotFound
 from google.cloud.secretmanager_v1.types import AccessSecretVersionResponse
-from parameterized import parameterized
 
 from airflow.exceptions import AirflowException
 from airflow.models import Connection
@@ -46,7 +46,7 @@ MODULE_NAME = "airflow.providers.google.cloud.secrets.secret_manager"
 CLIENT_MODULE_NAME = "airflow.providers.google.cloud._internal_client.secret_manager_client"
 
 
-class TestCloudSecretManagerBackend(TestCase):
+class TestCloudSecretManagerBackend:
     @mock.patch(MODULE_NAME + ".get_credentials_and_project_id")
     @mock.patch(CLIENT_MODULE_NAME + ".SecretManagerServiceClient")
     def test_default_valid_and_sep(self, mock_client_callable, mock_get_creds):
@@ -57,31 +57,32 @@ class TestCloudSecretManagerBackend(TestCase):
         backend = CloudSecretManagerBackend()
         assert backend._is_valid_prefix_and_sep()
 
-    @parameterized.expand(
+    @pytest.mark.parametrize(
+        "prefix, sep",
         [
-            ("colon:", "not:valid", ":"),
-            ("slash/", "not/valid", "/"),
-            ("space_with_char", "a b", ""),
-            ("space_only", "", " "),
-        ]
+            pytest.param("not:valid", ":", id="colon separator"),
+            pytest.param("not/valid", "/", id="backslash separator"),
+            pytest.param("a b", "", id="space with char and empty separator"),
+            pytest.param(" ", "", id="space only and empty separator"),
+        ],
     )
-    def test_raise_exception_with_invalid_prefix_sep(self, _, prefix, sep):
+    def test_raise_exception_with_invalid_prefix_sep(self, prefix, sep):
         with pytest.raises(AirflowException):
             CloudSecretManagerBackend(connections_prefix=prefix, sep=sep)
 
-    @parameterized.expand(
+    @pytest.mark.parametrize(
+        "prefix, sep, is_valid",
         [
-            ("dash-", "valid1", "-", True),
-            ("underscore_", "isValid", "_", True),
-            ("empty_string", "", "", True),
-            ("space_prefix", " ", "", False),
-            ("space_sep", "", " ", False),
-            ("colon:", "not:valid", ":", False),
-        ]
+            pytest.param("valid1", "-", True, id="valid: dash separator"),
+            pytest.param("isValid", "_", True, id="valid: underscore separator"),
+            pytest.param("", "", True, id="valid: empty string and empty separator"),
+            pytest.param("", " ", False, id="invalid: empty string and space separator"),
+            pytest.param("not:valid", ":", False, id="invalid: colon separator"),
+        ],
     )
     @mock.patch(MODULE_NAME + ".get_credentials_and_project_id")
     @mock.patch(CLIENT_MODULE_NAME + ".SecretManagerServiceClient")
-    def test_is_valid_prefix_and_sep(self, _, prefix, sep, is_valid, mock_client_callable, mock_get_creds):
+    def test_is_valid_prefix_and_sep(self, mock_client_callable, mock_get_creds, prefix, sep, is_valid):
         mock_get_creds.return_value = CREDENTIALS, PROJECT_ID
         mock_client = mock.MagicMock()
         mock_client_callable.return_value = mock_client
@@ -90,10 +91,10 @@ class TestCloudSecretManagerBackend(TestCase):
         backend.sep = sep
         assert backend._is_valid_prefix_and_sep() == is_valid
 
-    @parameterized.expand(["airflow-connections", "connections", "airflow"])
+    @pytest.mark.parametrize("connections_prefix", ["airflow-connections", "connections", "airflow"])
     @mock.patch(MODULE_NAME + ".get_credentials_and_project_id")
     @mock.patch(CLIENT_MODULE_NAME + ".SecretManagerServiceClient")
-    def test_get_conn_uri(self, connections_prefix, mock_client_callable, mock_get_creds):
+    def test_get_conn_uri(self, mock_client_callable, mock_get_creds, connections_prefix):
         mock_get_creds.return_value = CREDENTIALS, PROJECT_ID
         mock_client = mock.MagicMock()
         mock_client_callable.return_value = mock_client
@@ -118,7 +119,7 @@ class TestCloudSecretManagerBackend(TestCase):
 
     @mock.patch(MODULE_NAME + ".get_credentials_and_project_id")
     @mock.patch(CLIENT_MODULE_NAME + ".SecretManagerServiceClient")
-    def test_get_conn_uri_non_existent_key(self, mock_client_callable, mock_get_creds):
+    def test_get_conn_uri_non_existent_key(self, mock_client_callable, mock_get_creds, caplog):
         mock_get_creds.return_value = CREDENTIALS, PROJECT_ID
         mock_client = mock.MagicMock()
         mock_client_callable.return_value = mock_client
@@ -127,18 +128,18 @@ class TestCloudSecretManagerBackend(TestCase):
 
         secrets_manager_backend = CloudSecretManagerBackend(connections_prefix=CONNECTIONS_PREFIX)
         secret_id = secrets_manager_backend.build_path(CONNECTIONS_PREFIX, CONN_ID, SEP)
-        with self.assertLogs(secrets_manager_backend.client.log, level="DEBUG") as log_output:
+        with caplog.at_level(level=logging.DEBUG, logger=secrets_manager_backend.client.log.name):
             assert secrets_manager_backend.get_conn_uri(conn_id=CONN_ID) is None
             assert secrets_manager_backend.get_connection(conn_id=CONN_ID) is None
             assert re.search(
                 f"Google Cloud API Call Error \\(NotFound\\): Secret ID {secret_id} not found",
-                log_output.output[0],
+                caplog.messages[0],
             )
 
-    @parameterized.expand(["airflow-variables", "variables", "airflow"])
+    @pytest.mark.parametrize("variables_prefix", ["airflow-variables", "variables", "airflow"])
     @mock.patch(MODULE_NAME + ".get_credentials_and_project_id")
     @mock.patch(CLIENT_MODULE_NAME + ".SecretManagerServiceClient")
-    def test_get_variable(self, variables_prefix, mock_client_callable, mock_get_creds):
+    def test_get_variable(self, mock_client_callable, mock_get_creds, variables_prefix):
         mock_get_creds.return_value = CREDENTIALS, PROJECT_ID
         mock_client = mock.MagicMock()
         mock_client_callable.return_value = mock_client
@@ -153,10 +154,10 @@ class TestCloudSecretManagerBackend(TestCase):
         assert VAR_VALUE == returned_uri
         mock_client.secret_version_path.assert_called_once_with(PROJECT_ID, secret_id, "latest")
 
-    @parameterized.expand(["airflow-config", "config", "airflow"])
+    @pytest.mark.parametrize("config_prefix", ["airflow-config", "config", "airflow"])
     @mock.patch(MODULE_NAME + ".get_credentials_and_project_id")
     @mock.patch(CLIENT_MODULE_NAME + ".SecretManagerServiceClient")
-    def test_get_config(self, config_prefix, mock_client_callable, mock_get_creds):
+    def test_get_config(self, mock_client_callable, mock_get_creds, config_prefix):
         mock_get_creds.return_value = CREDENTIALS, PROJECT_ID
         mock_client = mock.MagicMock()
         mock_client_callable.return_value = mock_client
@@ -171,10 +172,10 @@ class TestCloudSecretManagerBackend(TestCase):
         assert CONFIG_VALUE == returned_val
         mock_client.secret_version_path.assert_called_once_with(PROJECT_ID, secret_id, "latest")
 
-    @parameterized.expand(["airflow-variables", "variables", "airflow"])
+    @pytest.mark.parametrize("variables_prefix", ["airflow-variables", "variables", "airflow"])
     @mock.patch(MODULE_NAME + ".get_credentials_and_project_id")
     @mock.patch(CLIENT_MODULE_NAME + ".SecretManagerServiceClient")
-    def test_get_variable_override_project_id(self, variables_prefix, mock_client_callable, mock_get_creds):
+    def test_get_variable_override_project_id(self, mock_client_callable, mock_get_creds, variables_prefix):
         mock_get_creds.return_value = CREDENTIALS, PROJECT_ID
         mock_client = mock.MagicMock()
         mock_client_callable.return_value = mock_client
@@ -193,7 +194,7 @@ class TestCloudSecretManagerBackend(TestCase):
 
     @mock.patch(MODULE_NAME + ".get_credentials_and_project_id")
     @mock.patch(CLIENT_MODULE_NAME + ".SecretManagerServiceClient")
-    def test_get_variable_non_existent_key(self, mock_client_callable, mock_get_creds):
+    def test_get_variable_non_existent_key(self, mock_client_callable, mock_get_creds, caplog):
         mock_get_creds.return_value = CREDENTIALS, PROJECT_ID
         mock_client = mock.MagicMock()
         mock_client_callable.return_value = mock_client
@@ -202,11 +203,11 @@ class TestCloudSecretManagerBackend(TestCase):
 
         secrets_manager_backend = CloudSecretManagerBackend(variables_prefix=VARIABLES_PREFIX)
         secret_id = secrets_manager_backend.build_path(VARIABLES_PREFIX, VAR_KEY, SEP)
-        with self.assertLogs(secrets_manager_backend.client.log, level="DEBUG") as log_output:
+        with caplog.at_level(level=logging.DEBUG, logger=secrets_manager_backend.client.log.name):
             assert secrets_manager_backend.get_variable(VAR_KEY) is None
             assert re.search(
                 f"Google Cloud API Call Error \\(NotFound\\): Secret ID {secret_id} not found",
-                log_output.output[0],
+                caplog.messages[0],
             )
 
     @mock.patch(MODULE_NAME + ".get_credentials_and_project_id")
diff --git a/tests/providers/google/cloud/utils/test_credentials_provider.py b/tests/providers/google/cloud/utils/test_credentials_provider.py
index d618f653d9..fe792ec290 100644
--- a/tests/providers/google/cloud/utils/test_credentials_provider.py
+++ b/tests/providers/google/cloud/utils/test_credentials_provider.py
@@ -20,8 +20,6 @@ import json
 import logging
 import os
 import re
-import unittest
-from contextlib import contextmanager
 from io import StringIO
 from unittest import mock
 from unittest.mock import ANY
@@ -29,7 +27,6 @@ from uuid import uuid4
 
 import pytest
 from google.auth.environment_vars import CREDENTIALS
-from parameterized import parameterized
 
 from airflow.exceptions import AirflowException
 from airflow.providers.google.cloud.utils.credentials_provider import (
@@ -56,7 +53,7 @@ ANOTHER_PROJECT_ID = "another_project_id"
 CRED_PROVIDER_LOGGER_NAME = "airflow.providers.google.cloud.utils.credentials_provider._CredentialProvider"
 
 
-class TestHelper(unittest.TestCase):
+class TestHelper:
     def test_build_gcp_conn_path(self):
         value = "test"
         conn = build_gcp_conn(key_file_path=value)
@@ -73,7 +70,7 @@ class TestHelper(unittest.TestCase):
         assert "google-cloud-platform://?projects=test" == conn
 
 
-class TestProvideGcpCredentials(unittest.TestCase):
+class TestProvideGcpCredentials:
     @mock.patch.dict(os.environ, {CREDENTIALS: ENV_VALUE})
     @mock.patch("tempfile.NamedTemporaryFile")
     def test_provide_gcp_credentials_key_content(self, mock_file):
@@ -98,7 +95,7 @@ class TestProvideGcpCredentials(unittest.TestCase):
         assert os.environ[CREDENTIALS] == ENV_VALUE
 
 
-class TestProvideGcpConnection(unittest.TestCase):
+class TestProvideGcpConnection:
     @mock.patch.dict(os.environ, {AIRFLOW_CONN_GOOGLE_CLOUD_DEFAULT: ENV_VALUE})
     @mock.patch("airflow.providers.google.cloud.utils.credentials_provider.build_gcp_conn")
     def test_provide_gcp_connection(self, mock_builder):
@@ -112,7 +109,7 @@ class TestProvideGcpConnection(unittest.TestCase):
         assert os.environ[AIRFLOW_CONN_GOOGLE_CLOUD_DEFAULT] == ENV_VALUE
 
 
-class TestProvideGcpConnAndCredentials(unittest.TestCase):
+class TestProvideGcpConnAndCredentials:
     @mock.patch.dict(
         os.environ,
         {AIRFLOW_CONN_GOOGLE_CLOUD_DEFAULT: ENV_VALUE, CREDENTIALS: ENV_VALUE},
@@ -131,35 +128,21 @@ class TestProvideGcpConnAndCredentials(unittest.TestCase):
         assert os.environ[CREDENTIALS] == ENV_VALUE
 
 
-class TestGetGcpCredentialsAndProjectId(unittest.TestCase):
-    @classmethod
-    def setUpClass(cls):
-        cls.test_scopes = _DEFAULT_SCOPES
-        cls.test_key_file = "KEY_PATH.json"
-        cls.test_project_id = "project_id"
-
-    @contextmanager
-    def assert_no_logs(self, name, level):
-        with self.assertLogs(level=level) as logs:
-            # AssertionError will raise if we do not create dummy record here
-            logging.log(level=logging.getLevelName(level), msg="nothing")
-            yield
-        records = [log_record for log_record in logs.records if log_record.name == name]
-        if not records:
-            return
-        raise AssertionError(f"Did not expect any log message from logger={name!r}, but got: {records}")
+class TestGetGcpCredentialsAndProjectId:
+    test_scopes = _DEFAULT_SCOPES
+    test_key_file = "KEY_PATH.json"
+    test_project_id = "project_id"
 
     @mock.patch("google.auth.default", return_value=("CREDENTIALS", "PROJECT_ID"))
-    def test_get_credentials_and_project_id_with_default_auth(self, mock_auth_default):
-        with self.assertLogs(logger=CRED_PROVIDER_LOGGER_NAME) as cm:
+    def test_get_credentials_and_project_id_with_default_auth(self, mock_auth_default, caplog):
+        with caplog.at_level(level=logging.INFO, logger=CRED_PROVIDER_LOGGER_NAME):
+            caplog.clear()
             result = get_credentials_and_project_id()
         mock_auth_default.assert_called_once_with(scopes=None)
         assert ("CREDENTIALS", "PROJECT_ID") == result
-        assert [
-            "INFO:airflow.providers.google.cloud.utils.credentials_provider._CredentialProvider:Getting "
-            "connection using `google.auth.default()` since no key file is defined for "
-            "hook."
-        ] == cm.output
+        assert (
+            "Getting connection using `google.auth.default()` since no key file is defined for hook."
+        ) in caplog.messages
 
     @mock.patch("google.auth.default")
     def test_get_credentials_and_project_id_with_default_auth_and_delegate(self, mock_auth_default):
@@ -171,9 +154,9 @@ class TestGetGcpCredentialsAndProjectId(unittest.TestCase):
         mock_credentials.with_subject.assert_called_once_with("USER")
         assert (mock_credentials.with_subject.return_value, self.test_project_id) == result
 
-    @parameterized.expand([(["scope1"],), (["scope1", "scope2"],)])
+    @pytest.mark.parametrize("scopes", [["scope1"], ["scope1", "scope2"]])
     @mock.patch("google.auth.default")
-    def test_get_credentials_and_project_id_with_default_auth_and_scopes(self, scopes, mock_auth_default):
+    def test_get_credentials_and_project_id_with_default_auth_and_scopes(self, mock_auth_default, scopes):
         mock_credentials = mock.MagicMock()
         mock_auth_default.return_value = (mock_credentials, self.test_project_id)
 
@@ -252,36 +235,38 @@ class TestGetGcpCredentialsAndProjectId(unittest.TestCase):
     @mock.patch(
         "google.oauth2.service_account.Credentials.from_service_account_file",
     )
-    def test_get_credentials_and_project_id_with_service_account_file(self, mock_from_service_account_file):
+    def test_get_credentials_and_project_id_with_service_account_file(
+        self, mock_from_service_account_file, caplog
+    ):
         mock_from_service_account_file.return_value.project_id = self.test_project_id
-        with self.assertLogs(level="DEBUG", logger=CRED_PROVIDER_LOGGER_NAME) as cm:
+        with caplog.at_level(level=logging.DEBUG, logger=CRED_PROVIDER_LOGGER_NAME):
+            caplog.clear()
             result = get_credentials_and_project_id(key_path=self.test_key_file)
         mock_from_service_account_file.assert_called_once_with(self.test_key_file, scopes=None)
         assert (mock_from_service_account_file.return_value, self.test_project_id) == result
-        assert [
-            "DEBUG:airflow.providers.google.cloud.utils.credentials_provider._CredentialProvider:Getting "
-            "connection using JSON key file KEY_PATH.json"
-        ] == cm.output
+        assert "Getting connection using JSON key file KEY_PATH.json" in caplog.messages
 
-    @parameterized.expand([("p12", "path/to/file.p12"), ("unknown", "incorrect_file.ext")])
-    def test_get_credentials_and_project_id_with_service_account_file_and_non_valid_key(self, _, file):
+    @pytest.mark.parametrize(
+        "file", [pytest.param("path/to/file.p12", id="p12"), pytest.param("incorrect_file.ext", id="unknown")]
+    )
+    def test_get_credentials_and_project_id_with_service_account_file_and_non_valid_key(self, file):
         with pytest.raises(AirflowException):
             get_credentials_and_project_id(key_path=file)
 
     @mock.patch(
         "google.oauth2.service_account.Credentials.from_service_account_info",
     )
-    def test_get_credentials_and_project_id_with_service_account_info(self, mock_from_service_account_info):
+    def test_get_credentials_and_project_id_with_service_account_info(
+        self, mock_from_service_account_info, caplog
+    ):
         mock_from_service_account_info.return_value.project_id = self.test_project_id
         service_account = {"private_key": "PRIVATE_KEY"}
-        with self.assertLogs(level="DEBUG", logger=CRED_PROVIDER_LOGGER_NAME) as cm:
+        with caplog.at_level(level=logging.DEBUG, logger=CRED_PROVIDER_LOGGER_NAME):
+            caplog.clear()
             result = get_credentials_and_project_id(keyfile_dict=service_account)
         mock_from_service_account_info.assert_called_once_with(service_account, scopes=None)
         assert (mock_from_service_account_info.return_value, self.test_project_id) == result
-        assert [
-            "DEBUG:airflow.providers.google.cloud.utils.credentials_provider._CredentialProvider:Getting "
-            "connection using JSON Dict"
-        ] == cm.output
+        assert "Getting connection using JSON Dict" in caplog.messages
 
     @mock.patch("google.auth.default", return_value=("CREDENTIALS", "PROJECT_ID"))
     @mock.patch("google.oauth2.service_account.Credentials.from_service_account_info")
@@ -337,71 +322,73 @@ class TestGetGcpCredentialsAndProjectId(unittest.TestCase):
     @mock.patch(
         "google.oauth2.service_account.Credentials.from_service_account_file",
     )
-    def test_disable_logging(self, mock_default, mock_info, mock_file):
-        """
-        Test disable logging in ``get_credentials_and_project_id``.
-
-        Due to following limitations, we use some workarounds for filtering specific logger
-        and raise error with these records:
-        - Cannot use pytest autouse-fixture `caplog` with `unittest.TestCase`
-        - `unittest.TestCase.assertNoLogs` available only in Python 3.10+
-        """
+    def test_disable_logging(self, mock_default, mock_info, mock_file, caplog):
+        """Test disable logging in ``get_credentials_and_project_id``"""
+
         # assert no logs
-        with self.assert_no_logs(name=CRED_PROVIDER_LOGGER_NAME, level="DEBUG"):
+        with caplog.at_level(level=logging.DEBUG, logger=CRED_PROVIDER_LOGGER_NAME):
+            caplog.clear()
             get_credentials_and_project_id(disable_logging=True)
+            assert not caplog.record_tuples
 
         # assert no debug logs emitted from get_credentials_and_project_id
-        with self.assert_no_logs(name=CRED_PROVIDER_LOGGER_NAME, level="DEBUG"):
+        with caplog.at_level(level=logging.DEBUG, logger=CRED_PROVIDER_LOGGER_NAME):
+            caplog.clear()
             get_credentials_and_project_id(
                 keyfile_dict={"private_key": "PRIVATE_KEY"},
                 disable_logging=True,
             )
+            assert not caplog.record_tuples
 
         # assert no debug logs emitted from get_credentials_and_project_id
-        with self.assert_no_logs(name=CRED_PROVIDER_LOGGER_NAME, level="DEBUG"):
+        with caplog.at_level(level=logging.DEBUG, logger=CRED_PROVIDER_LOGGER_NAME):
+            caplog.clear()
             get_credentials_and_project_id(
                 key_path="KEY.json",
                 disable_logging=True,
             )
+            assert not caplog.record_tuples
 
 
-class TestGetScopes(unittest.TestCase):
+class TestGetScopes:
     def test_get_scopes_with_default(self):
         assert _get_scopes() == _DEFAULT_SCOPES
 
-    @parameterized.expand(
+    @pytest.mark.parametrize(
+        "scopes_str, scopes",
         [
-            ("single_scope", "scope1", ["scope1"]),
-            ("multiple_scopes", "scope1,scope2", ["scope1", "scope2"]),
-        ]
+            pytest.param("scope1", ["scope1"], id="single-scope"),
+            pytest.param("scope1,scope2", ["scope1", "scope2"], id="multiple-scopes"),
+        ],
     )
-    def test_get_scopes_with_input(self, _, scopes_str, scopes):
+    def test_get_scopes_with_input(self, scopes_str, scopes):
         assert _get_scopes(scopes_str) == scopes
 
 
-class TestGetTargetPrincipalAndDelegates(unittest.TestCase):
+class TestGetTargetPrincipalAndDelegates:
     def test_get_target_principal_and_delegates_no_argument(self):
         assert _get_target_principal_and_delegates() == (None, None)
 
-    @parameterized.expand(
+    @pytest.mark.parametrize(
+        "impersonation_chain, target_principal_and_delegates",
         [
-            ("string", ACCOUNT_1_SAME_PROJECT, (ACCOUNT_1_SAME_PROJECT, None)),
-            ("empty_list", [], (None, None)),
-            ("single_element_list", [ACCOUNT_1_SAME_PROJECT], (ACCOUNT_1_SAME_PROJECT, [])),
-            (
-                "multiple_elements_list",
+            pytest.param(ACCOUNT_1_SAME_PROJECT, (ACCOUNT_1_SAME_PROJECT, None), id="string"),
+            pytest.param([], (None, None), id="empty-list"),
+            pytest.param([ACCOUNT_1_SAME_PROJECT], (ACCOUNT_1_SAME_PROJECT, []), id="single-element-list"),
+            pytest.param(
                 [ACCOUNT_1_SAME_PROJECT, ACCOUNT_2_SAME_PROJECT, ACCOUNT_3_ANOTHER_PROJECT],
                 (ACCOUNT_3_ANOTHER_PROJECT, [ACCOUNT_1_SAME_PROJECT, ACCOUNT_2_SAME_PROJECT]),
+                id="multiple-elements-list",
             ),
-        ]
+        ],
     )
     def test_get_target_principal_and_delegates_with_input(
-        self, _, impersonation_chain, target_principal_and_delegates
+        self, impersonation_chain, target_principal_and_delegates
     ):
         assert _get_target_principal_and_delegates(impersonation_chain) == target_principal_and_delegates
 
 
-class TestGetProjectIdFromServiceAccountEmail(unittest.TestCase):
+class TestGetProjectIdFromServiceAccountEmail:
     def test_get_project_id_from_service_account_email(self):
         assert _get_project_id_from_service_account_email(ACCOUNT_3_ANOTHER_PROJECT) == ANOTHER_PROJECT_ID
 
diff --git a/tests/providers/google/cloud/utils/test_field_sanitizer.py b/tests/providers/google/cloud/utils/test_field_sanitizer.py
index 0dc93a03f8..98220b1f1b 100644
--- a/tests/providers/google/cloud/utils/test_field_sanitizer.py
+++ b/tests/providers/google/cloud/utils/test_field_sanitizer.py
@@ -16,7 +16,6 @@
 # under the License.
 from __future__ import annotations
 
-import unittest
 from copy import deepcopy
 
 import pytest
@@ -24,7 +23,7 @@ import pytest
 from airflow.providers.google.cloud.utils.field_sanitizer import GcpBodyFieldSanitizer
 
 
-class TestGcpBodyFieldSanitizer(unittest.TestCase):
+class TestGcpBodyFieldSanitizer:
     def test_sanitize_should_sanitize_empty_body_and_fields(self):
         body = {}
         fields_to_sanitize = []
diff --git a/tests/providers/google/cloud/utils/test_field_validator.py b/tests/providers/google/cloud/utils/test_field_validator.py
index 0eb1382b70..920636e724 100644
--- a/tests/providers/google/cloud/utils/test_field_validator.py
+++ b/tests/providers/google/cloud/utils/test_field_validator.py
@@ -16,8 +16,6 @@
 # under the License.
 from __future__ import annotations
 
-import unittest
-
 import pytest
 
 from airflow.providers.google.cloud.utils.field_validator import (
@@ -27,7 +25,7 @@ from airflow.providers.google.cloud.utils.field_validator import (
 )
 
 
-class TestGcpBodyFieldValidator(unittest.TestCase):
+class TestGcpBodyFieldValidator:
     def test_validate_should_not_raise_exception_if_field_and_body_are_both_empty(self):
         specification = []
         body = {}
diff --git a/tests/providers/google/cloud/utils/test_mlengine_operator_utils.py b/tests/providers/google/cloud/utils/test_mlengine_operator_utils.py
index 88b801a94c..7c9be7f5a0 100644
--- a/tests/providers/google/cloud/utils/test_mlengine_operator_utils.py
+++ b/tests/providers/google/cloud/utils/test_mlengine_operator_utils.py
@@ -18,7 +18,6 @@ from __future__ import annotations
 
 import base64
 import json
-import unittest
 from datetime import datetime
 from unittest import mock
 
@@ -92,7 +91,7 @@ def validate_err_and_count(summary):
     return summary
 
 
-class TestMlengineOperatorUtils(unittest.TestCase):
+class TestMlengineOperatorUtils:
     @mock.patch.object(PythonOperator, "set_upstream")
     @mock.patch.object(BeamRunPythonPipelineOperator, "set_upstream")
     def test_create_evaluate_ops(self, mock_beam_pipeline, mock_python):
diff --git a/tests/providers/google/cloud/utils/test_mlengine_prediction_summary.py b/tests/providers/google/cloud/utils/test_mlengine_prediction_summary.py
index a6aaae1049..0bf647399d 100644
--- a/tests/providers/google/cloud/utils/test_mlengine_prediction_summary.py
+++ b/tests/providers/google/cloud/utils/test_mlengine_prediction_summary.py
@@ -18,7 +18,6 @@ from __future__ import annotations
 
 import base64
 import binascii
-import unittest
 from unittest import mock
 
 import dill
@@ -31,7 +30,7 @@ except ImportError as e:
         pytestmark = pytest.mark.skip(f"package apache_beam not present. Skipping all tests in {__name__}")
 
 
-class TestJsonCode(unittest.TestCase):
+class TestJsonCode:
     def test_encode(self):
         assert b'{"a": 1}' == mlengine_prediction_summary.JsonCoder.encode({"a": 1})
 
@@ -39,7 +38,7 @@ class TestJsonCode(unittest.TestCase):
         assert {"a": 1} == mlengine_prediction_summary.JsonCoder.decode('{"a": 1}')
 
 
-class TestMakeSummary(unittest.TestCase):
+class TestMakeSummary:
     def test_make_summary(self):
         print(mlengine_prediction_summary.MakeSummary(1, lambda x: x, []))