Skip to content

Commit 7760942

Browse files
committed
PR suggestions
1 parent 7c49c55 commit 7760942

File tree

1 file changed

+29
-47
lines changed

1 file changed

+29
-47
lines changed

articles/azure-functions/durable/durable-functions-unit-testing-python.md

Lines changed: 29 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,13 @@ ms.author: azfuncdf
99

1010
# Unit Testing Durable Functions in Python
1111

12-
## Introduction
13-
Unit testing Durable Functions is essential to ensure the correctness of individual components without relying on an actual Azure environment. By writing effective unit tests, developers can catch errors early, improve code maintainability, and increase confidence in their implementations.
12+
Unit testing is an important part of modern software development practices. Unit tests verify business logic behavior and protect from introducing unnoticed breaking changes in the future. Durable Functions can easily grow in complexity so introducing unit tests will help to avoid breaking changes. The following sections explain how to unit test the three function types - Orchestration client, orchestrator, and entity functions.
1413

15-
This guide provides an overview of unit testing Durable Functions in Python, covering the key components: starter functions, orchestrators, activity functions, and entity functions. It includes best practices and sample test cases to help you write robust and maintainable tests for your Durable Functions.
16-
17-
[!NOTE]
18-
This guide applies only to Durable Functions apps written in the [Python v2 programming model](../functions-reference-python.md).
14+
> [!NOTE]
15+
> This guide applies only to Durable Functions apps written in the [Python v2 programming model](../functions-reference-python.md).
1916
2017
## Prerequisites
18+
2119
The examples in this article require knowledge of the following concepts and frameworks:
2220

2321
* Unit testing
@@ -26,17 +24,18 @@ The examples in this article require knowledge of the following concepts and fra
2624
* [unittest.mock](https://docs.python.org/3/library/unittest.mock.html)
2725

2826
## Setting Up the Test Environment
27+
2928
To test Durable Functions, it's crucial to set up a proper test environment. This includes creating a test directory and installing unittest into your Python environment. For more info, see the [Azure Functions Python unit testing overview](../functions-reference-python.md#unit-testing).
3029

31-
## Testing Durable Clients
32-
Durable Client functions initiate orchestrations and external events. To test a client function:
30+
## Unit testing trigger functions
31+
32+
Trigger functions, often referred to as _client_ functions, initiate orchestrations and external events. To test these functions:
3333

3434
- Mock the `DurableOrchestrationClient` to simulate orchestration execution and status management.
35-
- Replace `DurableOrchestrationClient` methods such as `start_new`, `get_status`, or `raise_event` with mock functions that return expected values.
35+
- Assign `DurableOrchestrationClient` methods such as `start_new`, `get_status`, or `raise_event` with mock functions that return expected values.
3636
- Invoke the client function directly with a mocked client as well as other necessary inputs such as a `req` (HTTP request object) for HTTP trigger client functions.
3737
- Use assertions and `unittest.mock` tools to verify expected orchestration start behavior, parameters, and HTTP responses.
3838

39-
**Sample Code:**
4039
```python
4140
import asyncio
4241
import unittest
@@ -47,36 +46,35 @@ from function_app import start_orchestrator
4746

4847
class TestFunction(unittest.TestCase):
4948
@patch('azure.durable_functions.DurableOrchestrationClient')
50-
def test_chaining_orchestrator(self, client):
49+
def test_HttpStart(self, client):
5150
# Get the original method definition as seen in the function_app.py file
52-
# func_call = chaining_orchestrator.build().get_user_function_unmodified()
53-
func_call = start_orchestrator.build().get_user_function().client_function
51+
func_call = http_start.build().get_user_function().client_function
5452

5553
req = func.HttpRequest(method='GET',
56-
body=None,
54+
body=b'{}',
5755
url='/api/my_second_function',
58-
params={"orchestrator_name": "startOrchestrator"})
56+
route_params={"functionName": "my_orchestrator"})
5957

6058
client.start_new = AsyncMock(return_value="instance_id")
6159
client.create_check_status_response = Mock(return_value="check_status_response")
6260

63-
# Create a generator using the method and mocked context
61+
# Execute the function code
6462
result = asyncio.run(func_call(req, client))
6563

66-
client.start_new.assert_called_once_with("startOrchestrator")
64+
client.start_new.assert_called_once_with("my_orchestrator")
6765
client.create_check_status_response.assert_called_once_with(req, "instance_id")
6866
self.assertEqual(result, "check_status_response")
6967
```
7068

71-
## Testing Durable Orchestrators
72-
Durable Orchestrators manage the execution of multiple activity functions. To test an orchestrator:
69+
## Unit testing orchestrator functions
70+
71+
Orchestrator functions manage the execution of multiple activity functions. To test an orchestrator:
7372

7473
- Mock the `DurableOrchestrationContext` to control function execution.
7574
- Replace `DurableOrchestrationContext` methods needed for orchestrator execution like `call_activity` or `create_timer` with mock functions. These functions should have pre-determined behavior and should typically return Task objects with a `result` property.
7675
- Call the orchestrator recursively, passing the result of the Task generated by the previous yield statement to the next.
7776
- Use the results returned from the orchestrator, as well as `unittest.mock` methods to verify the orchestrator result.
7877

79-
**Sample Code:**
8078
```python
8179
import unittest
8280
from unittest.mock import Mock, patch, call
@@ -86,10 +84,10 @@ class TestFunction(unittest.TestCase):
8684
@patch('azure.durable_functions.DurableOrchestrationContext')
8785
def test_chaining_orchestrator(self, context):
8886
# Get the original method definition as seen in the function_app.py file
89-
func_call = chaining_orchestrator.build().get_user_function().orchestrator_function
87+
func_call = my_orchestrator.build().get_user_function().orchestrator_function
9088

9189
context.call_activity = Mock(side_effect=mock_activity)
92-
context.create_timer = Mock(return_value=MockTask())
90+
9391
# Create a generator using the method and mocked context
9492
user_orchestrator = func_call(context)
9593

@@ -102,19 +100,18 @@ class TestFunction(unittest.TestCase):
102100

103101
self.assertEqual(context.call_activity.call_count, 3)
104102
self.assertEqual(context.call_activity.call_args_list, expected_activity_calls)
105-
context.create_timer.assert_called_once_with(context.current_utc_datetime + timedelta(seconds=5))
106-
self.assertEqual(values[4], ["Hello Tokyo!", "Hello Seattle!", "Hello London!"])
103+
self.assertEqual(values[3], ["Hello Tokyo!", "Hello Seattle!", "Hello London!"])
107104
```
108105

109-
## Testing Durable Entities
110-
Durable Entity functions manage stateful objects with operations. To test an entity function:
106+
## Unit testing entity functions
107+
108+
Entity functions manage stateful objects with operations. To test an entity function:
111109

112110
- Mock the `DurableEntityContext` to simulate the entity's internal state and operation inputs.
113111
- Replace `DurableEntityContext` methods like `get_state`, `set_state`, and `operation_name` with mocks that return controlled values.
114112
- Invoke the entity function directly with the mocked context.
115113
- Use assertions to verify state changes and returned values, along with `unittest.mock` utilities.
116114

117-
**Sample Code:**
118115
```python
119116
import unittest
120117
from unittest.mock import Mock, patch
@@ -156,27 +153,12 @@ class TestEntityFunction(unittest.TestCase):
156153
self.assertEqual(result, None)
157154
```
158155

159-
## Testing Activity Functions
160-
Activity functions require no Durable-specific modifications to be tested. The guidance found in the [Azure Functions Python unit testing overview](../functions-reference-python.md#unit-testing) is sufficient for testing these functions.
161-
162-
## Summary
163-
Testing Durable Functions effectively requires simulating their unique runtime behaviors while keeping tests isolated and deterministic. Here are some best practices to keep in mind:
164-
165-
- **Mock the right context objects**: Use `DurableOrchestrationContext`, `DurableOrchestrationClient`, and `DurableEntityContext` mocks to simulate platform behavior.
166-
- **Replace key methods**: Mock critical methods like `call_activity`, `start_new`, `get_state`, etc., to return controlled values for validation.
167-
- **Isolate logic**: Keep orchestration, client, and entity logic testable independently to ensure clear separation of concerns.
168-
- **Validate behavior, not implementation**: Focus on validating the outcome and side effects, rather than internal steps.
169-
- **Use generator wrappers**: For orchestrators, properly walk through the generator steps to simulate orchestration flow.
170-
- **Test failure paths**: Include tests for error conditions, timeouts, and unexpected input to ensure robust function behavior.
171-
172-
By applying these practices, you can build a comprehensive test suite for your Durable Functions that ensures reliability and simplifies long-term maintenance.
156+
## Unit testing activity functions
173157

174-
---
158+
Activity functions require no Durable-specific modifications to be tested. The guidance found in the [Azure Functions Python unit testing overview](../functions-reference-python.md#unit-testing) is sufficient for testing these functions.
175159

176160
## Related content
177161

178-
For deeper insights into Durable Functions in Python, explore these resources:
179-
180-
- [Improve throughput performance of Python apps in Azure Functions](../python-scale-performance-reference.md)
181-
- [Azure Functions Python Developer Guide](../functions-reference-python.md)
182-
- [Durable Functions best practices and diagnostic tools](./durable-functions-best-practice-reference.md)
162+
- [Learn how to improve throughput performance of Python apps in Azure Functions](../python-scale-performance-reference.md)
163+
- [Read the Azure Functions Python Developer Guide](../functions-reference-python.md)
164+
- [Learn about Durable Functions best practices and diagnostic tools](./durable-functions-best-practice-reference.md)

0 commit comments

Comments
 (0)