Ескертпе
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Жүйеге кіруді немесе каталогтарды өзгертуді байқап көруге болады.
Бұл бетке кіру үшін қатынас шегін айқындау қажет. Каталогтарды өзгертуді байқап көруге болады.
Модульное тестирование является важной частью современных методик разработки программного обеспечения. Модульные тесты проверяют поведение бизнес-логики и защищают от внедрения незамеченных критических изменений в будущем. Устойчивые функции могут легко нарастать в сложности, поэтому внедрение модульных тестов помогает избежать нарушающих изменений. В следующих разделах объясняется, как выполнять модульное тестирование трех типов функций: клиента оркестрации, оркестратора и функций сущности.
Замечание
Это руководство относится только к приложениям устойчивых функций, написанным в модели программирования Python версии 2.
Предпосылки
В примерах этой статьи требуются знания о следующих понятиях и платформах:
- Модульное тестирование
- Устойчивые функции
- Модульный тест Python
- unittest.mock
Настройка тестовой среды
Чтобы протестировать устойчивые функции, важно настроить правильную тестовую среду. Это включает создание тестового каталога и установку модуля Python unittest в среду Python. Дополнительные сведения см. в обзоре модульного тестирования функций Python.
Функции триггера модульного тестирования
Функции триггера, часто называемые клиентскими функциями, инициируют оркестрации и внешние события. Чтобы проверить эти функции, выполните следующие действия:
- Смоделируйте
DurableOrchestrationClientдля симуляции выполнения оркестрации и управления состоянием. - Назначьте
DurableOrchestrationClientтакие методы, какstart_new,get_statusилиraise_eventс макетными функциями, возвращающими ожидаемые значения. - Вызовите клиентную функцию напрямую с макетным клиентом и другими необходимыми входными данными, такими как
reqобъект HTTP-запроса) для клиентских функций триггера HTTP. - Используйте утверждения и
unittest.mockсредства для проверки ожидаемого поведения запуска оркестрации, параметров и ответов HTTP.
import asyncio
import unittest
import azure.functions as func
from unittest.mock import AsyncMock, Mock, patch
from function_app import start_orchestrator
class TestFunction(unittest.TestCase):
@patch('azure.durable_functions.DurableOrchestrationClient')
def test_HttpStart(self, client):
# Get the original method definition as seen in the function_app.py file
func_call = http_start.build().get_user_function().client_function
req = func.HttpRequest(method='GET',
body=b'{}',
url='/api/my_second_function',
route_params={"functionName": "my_orchestrator"})
client.start_new = AsyncMock(return_value="instance_id")
client.create_check_status_response = Mock(return_value="check_status_response")
# Execute the function code
result = asyncio.run(func_call(req, client))
client.start_new.assert_called_once_with("my_orchestrator")
client.create_check_status_response.assert_called_once_with(req, "instance_id")
self.assertEqual(result, "check_status_response")
Функции оркестратора для модульного тестирования
Функции оркестратора управляют выполнением нескольких функций действий. Чтобы протестировать оркестратор, выполните приведенные действия.
- Используйте объект
DurableOrchestrationContextдля управления выполнением функции. - Замените
DurableOrchestrationContextметоды, необходимые для выполнения оркестратора, такие какcall_activityилиcreate_timer, на фиктивные функции. Обычно эти функции возвращают объекты типа TaskBase со свойствомresult. - Вызовите оркестратор рекурсивно, передав результат задачи, созданной предыдущим оператором yield, в следующую задачу.
- Проверьте результат оркестратора, используя результаты, возвращаемые из оркестратора и
unittest.mock.
import unittest
from unittest.mock import Mock, patch, call
from datetime import timedelta
from azure.durable_functions.testing import orchestrator_generator_wrapper
from function_app import my_orchestrator
class TestFunction(unittest.TestCase):
@patch('azure.durable_functions.DurableOrchestrationContext')
def test_chaining_orchestrator(self, context):
# Get the original method definition as seen in the function_app.py file
func_call = my_orchestrator.build().get_user_function().orchestrator_function
# The mock_activity method is defined above with behavior specific to your app.
# It returns a TaskBase object with the result expected from the activity call.
context.call_activity = Mock(side_effect=mock_activity)
# Create a generator using the method and mocked context
user_orchestrator = func_call(context)
# Use orchestrator_generator_wrapper to get the values from the generator.
# Processes the orchestrator in a way that is equivalent to the Durable replay logic
values = [val for val in orchestrator_generator_wrapper(user_orchestrator)]
expected_activity_calls = [call('say_hello', 'Tokyo'),
call('say_hello', 'Seattle'),
call('say_hello', 'London')]
self.assertEqual(context.call_activity.call_count, 3)
self.assertEqual(context.call_activity.call_args_list, expected_activity_calls)
self.assertEqual(values[3], ["Hello Tokyo!", "Hello Seattle!", "Hello London!"])
Функции сущности модульного тестирования
Функции сущностей управляют объектами с состоянием с помощью операций. Чтобы проверить функцию сущности, выполните приведенные действия.
- Имитируйте
DurableEntityContext, чтобы смоделировать внутреннее состояние сущности и вводимые данные операций. - Замените
DurableEntityContextметоды, такие какget_state,set_state, иoperation_name, макетами, возвращающими управляемые значения. - Вызовите функцию сущности непосредственно с помощью макетированного контекста.
- Используйте утверждения (assertions) для проверки изменений состояния и возвращаемых значений совместно с
unittest.mockутилитами.
import unittest
from unittest.mock import Mock, patch
from function_app import Counter
class TestEntityFunction(unittest.TestCase):
@patch('azure.durable_functions.DurableEntityContext')
def test_entity_add_operation(self, context_mock):
# Get the original method definition as seen in function_app.py
func_call = Counter.build().get_user_function().entity_function
# Setup mock context behavior
state = 0
result = None
def set_state(new_state):
nonlocal state
state = new_state
def set_result(new_result):
nonlocal result
result = new_result
context_mock.get_state = Mock(return_value=state)
context_mock.set_state = Mock(side_effect=set_state)
context_mock.operation_name = "add"
context_mock.get_input = Mock(return_value=5)
context_mock.set_result = Mock(side_effect=lambda x: set_result)
# Call the entity function with the mocked context
func_call(context_mock)
# Verify the state was updated correctly
context_mock.set_state.assert_called_once_with(5)
self.assertEqual(state, 5)
self.assertEqual(result, None)
Функции модульного тестирования в деятельности
Функции активности не требуют специфических для Durable модификаций для тестирования. Рекомендации, приведенные в обзоре модульного тестирования функций Python, достаточно для тестирования этих функций.