|
| 1 | +# Agents SDK for Python Testing |
| 2 | + |
| 3 | +This document serves as a quick guide to the utilities we provide internally to test this SDK. More information will come with work on integration testing. |
| 4 | + |
| 5 | +## Storage Tests |
| 6 | + |
| 7 | +More info soon. For now, there are flags defined in the code that dictate whether the Cosmos DB and the Blob storage tests are run, as these tests rely on local emulators. |
| 8 | + |
| 9 | +## Mocking |
| 10 | + |
| 11 | +When using a class or function that takes a `mocker` argument, it is highly recommended that you pass in the Pytest fixture obtained either in: |
| 12 | + |
| 13 | +a test |
| 14 | + |
| 15 | +```python |
| 16 | + def test_thing(self, some_fixture, mocker): |
| 17 | + mock_UserTokenClient(mocker) |
| 18 | +``` |
| 19 | + |
| 20 | +the setup method of a class |
| 21 | + |
| 22 | +```python |
| 23 | +class TestThing: |
| 24 | + |
| 25 | + def setup_method(self, mocker): |
| 26 | + self.msal_auth = MockMsalAuth(mocker) |
| 27 | +``` |
| 28 | + |
| 29 | +or in another fixture |
| 30 | + |
| 31 | +```python |
| 32 | + @pytest.fixture |
| 33 | + def user_token_client(self, mocker): |
| 34 | + return mock_OAuthFlow(mocker, get_user_token_return="token") |
| 35 | +``` |
| 36 | + |
| 37 | +This ensures Pytest will correctly manage the lifetime of your mocking logic to occur within the score of the individual test or class. |
| 38 | + |
| 39 | +## Directory Structure |
| 40 | + |
| 41 | + |
| 42 | +### Module Names |
| 43 | + |
| 44 | +This directory follows the same structure as the package structure. If there is a test module that tests the functionality of a module in the packages source code, then please use the format `test_{ORIGINAL_MODULE}.py` file naming convention. If a module is an extra module that only exists in testing and has no counterpart in the packages source code, then it is encouraged that you prefix it with an underscore. The only exception is if a parent (or ancestor) directory of the testing Python file already has an underscore prefix. For example: |
| 45 | + |
| 46 | +``` |
| 47 | +microsoft_agents/hosting/core |
| 48 | + __init__.py |
| 49 | +
|
| 50 | + _common/ |
| 51 | + __init__.py |
| 52 | + bar.py |
| 53 | +
|
| 54 | + app/ |
| 55 | + __init__.py |
| 56 | + _helper.py |
| 57 | + test_agent_application.py |
| 58 | +
|
| 59 | + _foo.py |
| 60 | + test_turn_context.py |
| 61 | + test_utils.py |
| 62 | +
|
| 63 | +``` |
| 64 | + |
| 65 | +### `tests/_common` |
| 66 | + |
| 67 | +This directory contains common utilities for testing. |
| 68 | + |
| 69 | +### `tests/_common/_tests` |
| 70 | + |
| 71 | +Tests for testing utilities. |
| 72 | + |
| 73 | +### `tests/_common/data` |
| 74 | + |
| 75 | +Here, we encourage defining the data within the constructors of a class. I guess this helps clean up imports, but the primary purpose is to prevent tests from mutating these testing constants and interfering with other tests. The `test_defaults.py` module defines defaults for fundamental variables such as `user_id` and `channel_id`. These defaults are used in tests as well as other data constructors in `tests/_common/data`. For instance `test_flow_data.py` builds on those defaults to define FlowState objects for testing, and then `tests/_common/storage_data` builds even further on that. |
| 76 | + |
| 77 | +### `tests/_common/storage` |
| 78 | + |
| 79 | +Storage related functionality. This was the first shared testing utility module, so this can eventually be reorganized into the rest of the `tests/_common` structure. |
| 80 | + |
| 81 | +### `tests/_common/fixtures` |
| 82 | + |
| 83 | +This directory holds common fixtures that might be useful. For instance, `FlowStateFixtures` provides fixtures that are useful for testing both the OAuthFlow and Authorization classes, and it relies on `tests/_common/data/test_flow_data.py` module. |
| 84 | + |
| 85 | +### `tests/_common/testing_objects` |
| 86 | + |
| 87 | +This directory contains implementations and functions to construct objects that implement/extend core Protocols or mock existing functionality. In this repo, `testing_{class_name}.py` modules contain simple implementations with predictable behavior while `mock_{class_name}.py` usually contain `mock_{class_name}` and `mock_class_{class_name}` functions that wrap existing instances/classes with Pytest's mocking capabilities. |
| 88 | + |
| 89 | +### `tests/_integration` |
| 90 | + |
| 91 | +At the moment, there is no actual real integration testing, but there is a foundation that lets you define an environmental setup and then run a "sample" on that environment. |
0 commit comments