|
| 1 | +# Microsoft 365 Agents SDK for Python - Testing Framework |
| 2 | + |
| 3 | +A comprehensive testing framework designed specifically for Microsoft 365 Agents SDK, providing essential utilities and abstractions to streamline integration testing, authentication, and end-to-end agent validation. |
| 4 | + |
| 5 | +## Why This Package Exists |
| 6 | + |
| 7 | +Building and testing conversational agents presents unique challenges that standard testing frameworks don't address. This package eliminates these pain points by providing useful abstractions specifically designed for agent testing scenarios. |
| 8 | + |
| 9 | +## Key Features |
| 10 | + |
| 11 | +### 🔐 Authentication Utilities |
| 12 | +- **OAuth2 Token Generation**: Generate access tokens using client credentials flow |
| 13 | +- **Configuration-Based Auth**: Load credentials from environment variables or config objects |
| 14 | +- **MSAL Integration**: Built-in support for Microsoft Authentication Library |
| 15 | + |
| 16 | +```python |
| 17 | +from microsoft_agents.testing import generate_token, generate_token_from_config |
| 18 | + |
| 19 | +# Generate token directly |
| 20 | +token = generate_token( |
| 21 | + app_id="your-app-id", |
| 22 | + app_secret="your-secret", |
| 23 | + tenant_id="your-tenant" |
| 24 | +) |
| 25 | + |
| 26 | +# Or from SDK config |
| 27 | +token = generate_token_from_config(sdk_config) |
| 28 | +``` |
| 29 | + |
| 30 | +### 🧪 Integration Test Framework |
| 31 | +- **Pytest Fixtures**: Pre-built fixtures for common test scenarios |
| 32 | +- **Environment Abstraction**: Reusable environment setup for different hosting configurations |
| 33 | +- **Sample Management**: Base classes for organizing test samples and configurations |
| 34 | +- **Application Runners**: Abstract server lifecycle management for integration tests |
| 35 | + |
| 36 | +```python |
| 37 | +from microsoft_agents.testing import Integration, Environment, Sample |
| 38 | + |
| 39 | +class MyAgentTests(Integration): |
| 40 | + _sample_cls = MyAgentSample |
| 41 | + _environment_cls = AiohttpEnvironment |
| 42 | + |
| 43 | + @pytest.mark.asyncio |
| 44 | + async def test_conversation_flow(self, agent_client, sample): |
| 45 | + # Client and sample are automatically set up via fixtures |
| 46 | + response = await agent_client.send_activity("Hello") |
| 47 | + assert response is not None |
| 48 | +``` |
| 49 | + |
| 50 | +### 🤖 Agent Communication Clients |
| 51 | +- **AgentClient**: High-level client for sending Activities to agents |
| 52 | +- **ResponseClient**: Handle responses from agent services |
| 53 | +- **Automatic Token Management**: Clients handle authentication automatically |
| 54 | +- **Delivery Mode Support**: Test both standard and `ExpectReplies` delivery patterns |
| 55 | + |
| 56 | +```python |
| 57 | +from microsoft_agents.testing import AgentClient |
| 58 | + |
| 59 | +client = AgentClient( |
| 60 | + agent_url="http://localhost:3978", |
| 61 | + cid="conversation-id", |
| 62 | + client_id="your-client-id", |
| 63 | + tenant_id="your-tenant-id", |
| 64 | + client_secret="your-secret" |
| 65 | +) |
| 66 | + |
| 67 | +# Send simple text message |
| 68 | +response = await client.send_activity("What's the weather?") |
| 69 | + |
| 70 | +# Send Activity with ExpectReplies |
| 71 | +replies = await client.send_expect_replies( |
| 72 | + Activity(type=ActivityTypes.message, text="Hello") |
| 73 | +) |
| 74 | +``` |
| 75 | + |
| 76 | +### 🛠️ Testing Utilities |
| 77 | +- **Activity Population**: Automatically fill default Activity properties for testing |
| 78 | +- **URL Parsing**: Extract host and port from service URLs |
| 79 | +- **Configuration Management**: Centralized SDK configuration for tests |
| 80 | + |
| 81 | +```python |
| 82 | +from microsoft_agents.testing import populate_activity, get_host_and_port |
| 83 | + |
| 84 | +# Populate test activity with defaults |
| 85 | +activity = populate_activity( |
| 86 | + Activity(text="Hello"), |
| 87 | + defaults={"service_url": "http://localhost", "channel_id": "test"} |
| 88 | +) |
| 89 | + |
| 90 | +# Parse service URLs |
| 91 | +host, port = get_host_and_port("http://localhost:3978/api/messages") |
| 92 | +``` |
| 93 | + |
| 94 | +## Who Should Use This Package |
| 95 | + |
| 96 | +- **Agent Developers**: Testing agents built with `microsoft-agents-hosting-core` and related packages |
| 97 | +- **QA Engineers**: Writing integration and E2E tests for conversational AI systems |
| 98 | +- **DevOps Teams**: Automating agent validation in CI/CD pipelines |
| 99 | +- **Sample Authors**: Creating reproducible examples and documentation |
| 100 | + |
| 101 | +## Integration with CI/CD |
| 102 | + |
| 103 | +This package is designed for seamless integration into continuous integration pipelines: |
| 104 | + |
| 105 | +```yaml |
| 106 | +# Example: GitHub Actions |
| 107 | +- name: Run Agent Integration Tests |
| 108 | + run: | |
| 109 | + pip install microsoft-agents-testing pytest pytest-asyncio |
| 110 | + pytest tests/integration/ -v |
| 111 | + env: |
| 112 | + CLIENT_ID: ${{ secrets.AGENT_CLIENT_ID }} |
| 113 | + CLIENT_SECRET: ${{ secrets.AGENT_CLIENT_SECRET }} |
| 114 | + TENANT_ID: ${{ secrets.TENANT_ID }} |
| 115 | +``` |
| 116 | +
|
| 117 | +## Quick Start Example |
| 118 | +
|
| 119 | +```python |
| 120 | +import pytest |
| 121 | +from microsoft_agents.testing import Integration, AiohttpEnvironment, Sample |
| 122 | +from microsoft_agents.activity import Activity |
| 123 | + |
| 124 | +class MyAgentSample(Sample): |
| 125 | + async def init_app(self): |
| 126 | + # Initialize your agent application |
| 127 | + self.app = create_my_agent_app(self.env) |
| 128 | + |
| 129 | + @classmethod |
| 130 | + async def get_config(cls): |
| 131 | + return {"service_url": "http://localhost:3978"} |
| 132 | + |
| 133 | +class TestMyAgent(Integration): |
| 134 | + _sample_cls = MyAgentSample |
| 135 | + _environment_cls = AiohttpEnvironment |
| 136 | + |
| 137 | + _agent_url = "http://localhost:3978" |
| 138 | + _cid = "test-conversation" |
| 139 | + |
| 140 | + @pytest.mark.asyncio |
| 141 | + async def test_greeting(self, agent_client): |
| 142 | + response = await agent_client.send_activity("Hello") |
| 143 | + assert "Hi there" in response |
| 144 | + |
| 145 | + @pytest.mark.asyncio |
| 146 | + async def test_conversation(self, agent_client): |
| 147 | + replies = await agent_client.send_expect_replies("What can you do?") |
| 148 | + assert len(replies) > 0 |
| 149 | + assert replies[0].type == "message" |
| 150 | +``` |
| 151 | +
|
| 152 | +## Related Packages |
| 153 | +
|
| 154 | +This package complements the Microsoft 365 Agents SDK ecosystem: |
| 155 | +
|
| 156 | +- `microsoft-agents-activity`: Activity types and protocols |
| 157 | +- `microsoft-agents-hosting-core`: Core hosting framework |
| 158 | +- `microsoft-agents-hosting-aiohttp`: aiohttp hosting integration |
| 159 | +- `microsoft-agents-authentication-msal`: MSAL authentication |
| 160 | + |
| 161 | +## Contributing |
| 162 | + |
| 163 | +This project welcomes contributions and suggestions. Most contributions require you to agree to a Contributor License Agreement (CLA). For details, visit [https://cla.opensource.microsoft.com](https://cla.opensource.microsoft.com). |
| 164 | + |
| 165 | +## License |
| 166 | + |
| 167 | +MIT |
| 168 | + |
| 169 | +## Support |
| 170 | + |
| 171 | +For issues, questions, or contributions, please visit the [GitHub repository](https://github.com/microsoft/Agents-for-python). |
0 commit comments