ec2b666284
Continuous Integration / Pre-commit Linter (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.10) (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.11) (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.12) (push) Has been cancelled
Continuous Integration / Mypy Check (Python 3.13) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.10) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.11) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.12) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.13) (push) Has been cancelled
Continuous Integration / Unit Tests (Python 3.14) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.10) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.11) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.12) (push) Has been cancelled
Copybara PR Handler / close-imported-pr (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.13) (push) Has been cancelled
Continuous Integration / A2A v0.3 Tests (Python 3.14) (push) Has been cancelled
111 lines
4.3 KiB
Python
111 lines
4.3 KiB
Python
# Copyright 2026 Google LLC
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
from unittest import mock
|
|
|
|
from google.adk.evaluation.custom_metric_evaluator import _CustomMetricEvaluator
|
|
from google.adk.evaluation.custom_metric_evaluator import _get_metric_function
|
|
from google.adk.evaluation.eval_case import ConversationScenario
|
|
from google.adk.evaluation.eval_case import Invocation
|
|
from google.adk.evaluation.eval_metrics import EvalMetric
|
|
from google.adk.evaluation.evaluator import EvaluationResult
|
|
import pytest
|
|
|
|
|
|
def my_sync_metric_function(
|
|
eval_metric: EvalMetric,
|
|
actual_invocations: list[Invocation],
|
|
expected_invocations: list[Invocation] | None,
|
|
conversation_scenario: ConversationScenario | None,
|
|
) -> EvaluationResult:
|
|
"""Sync metric function for testing."""
|
|
return EvaluationResult(overall_score=1.0)
|
|
|
|
|
|
async def my_async_metric_function(
|
|
eval_metric: EvalMetric,
|
|
actual_invocations: list[Invocation],
|
|
expected_invocations: list[Invocation] | None,
|
|
conversation_scenario: ConversationScenario | None,
|
|
) -> EvaluationResult:
|
|
"""Async metric function for testing."""
|
|
return EvaluationResult(overall_score=0.5)
|
|
|
|
|
|
@mock.patch("importlib.import_module")
|
|
def test_get_metric_function_success(mock_import_module):
|
|
"""Tests that _get_metric_function successfully returns a function."""
|
|
mock_module = mock.MagicMock()
|
|
mock_module.my_sync_metric_function = my_sync_metric_function
|
|
mock_import_module.return_value = mock_module
|
|
func = _get_metric_function(
|
|
"test_custom_metric_evaluator.my_sync_metric_function"
|
|
)
|
|
assert func == my_sync_metric_function
|
|
|
|
|
|
@mock.patch("importlib.import_module", side_effect=ImportError)
|
|
def test_get_metric_function_module_not_found(mock_import_module):
|
|
"""Tests that _get_metric_function raises ImportError for non-existent module."""
|
|
with pytest.raises(ImportError):
|
|
_get_metric_function("non_existent_module.my_sync_metric_function")
|
|
|
|
|
|
@mock.patch("importlib.import_module")
|
|
def test_get_metric_function_function_not_found(mock_import_module):
|
|
"""Tests that _get_metric_function raises ImportError for non-existent function."""
|
|
mock_import_module.return_value = object()
|
|
with pytest.raises(ImportError):
|
|
_get_metric_function(
|
|
"google.adk.tests.unittests.evaluation.test_custom_metric_evaluator.non_existent_function"
|
|
)
|
|
|
|
|
|
def test_get_metric_function_malformed_path():
|
|
"""Tests that _get_metric_function raises ImportError for malformed path."""
|
|
with pytest.raises(ImportError):
|
|
_get_metric_function("malformed_path")
|
|
|
|
|
|
@mock.patch(
|
|
"google.adk.evaluation.custom_metric_evaluator._get_metric_function",
|
|
return_value=my_sync_metric_function,
|
|
)
|
|
@pytest.mark.asyncio
|
|
async def test_custom_metric_evaluator_sync_function(mock_get_metric_function):
|
|
"""Tests that _CustomMetricEvaluator works with a sync metric function."""
|
|
eval_metric = EvalMetric(metric_name="sync_metric")
|
|
evaluator = _CustomMetricEvaluator(
|
|
eval_metric=eval_metric,
|
|
custom_function_path="google.adk.tests.unittests.evaluation.test_custom_metric_evaluator.my_sync_metric_function",
|
|
)
|
|
result = await evaluator.evaluate_invocations([], None)
|
|
assert result.overall_score == 1.0
|
|
|
|
|
|
@mock.patch(
|
|
"google.adk.evaluation.custom_metric_evaluator._get_metric_function",
|
|
return_value=my_async_metric_function,
|
|
)
|
|
@pytest.mark.asyncio
|
|
async def test_custom_metric_evaluator_async_function(mock_get_metric_function):
|
|
"""Tests that _CustomMetricEvaluator works with an async metric function."""
|
|
eval_metric = EvalMetric(metric_name="async_metric")
|
|
evaluator = _CustomMetricEvaluator(
|
|
eval_metric=eval_metric,
|
|
custom_function_path="google.adk.tests.unittests.evaluation.test_custom_metric_evaluator.my_async_metric_function",
|
|
)
|
|
result = await evaluator.evaluate_invocations([], None)
|
|
assert result.overall_score == 0.5
|