Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
84 commits
Select commit Hold shift + click to select a range
cfb8847
basic integration utility
rodrigobr-msft Oct 21, 2025
4d93a46
Integration test suite factory implementation
rodrigobr-msft Oct 23, 2025
be2fb1c
Implementing core models for integration testing
rodrigobr-msft Oct 23, 2025
0d5539a
AutoClient mockup
rodrigobr-msft Oct 23, 2025
bf4c006
Adding runner starter code
rodrigobr-msft Oct 23, 2025
ebe622d
Adding foundational classes
rodrigobr-msft Oct 25, 2025
45678e9
Drafting AgentClient and ResponseClient implementations
rodrigobr-msft Oct 27, 2025
c2b84cb
Spec test
rodrigobr-msft Oct 27, 2025
2816e68
Filling in more implementation details
rodrigobr-msft Oct 27, 2025
2214827
More files
rodrigobr-msft Oct 27, 2025
c90c8e4
Cleaning up implementations
rodrigobr-msft Oct 29, 2025
36f5c3b
Adding expect replies sending method
rodrigobr-msft Oct 29, 2025
dfdd959
Beginning unit tests
rodrigobr-msft Oct 30, 2025
d4828fb
Adding integration decor from sample test cases
rodrigobr-msft Oct 30, 2025
91b3c44
Integration from service url tests
rodrigobr-msft Oct 31, 2025
1eefe44
_handle_conversation implementation for response_client
rodrigobr-msft Oct 31, 2025
a06da9a
AgentClient tests completed
rodrigobr-msft Oct 31, 2025
d36ec7a
Creating response client tests
rodrigobr-msft Nov 3, 2025
c096048
Hosting server for response client
rodrigobr-msft Nov 3, 2025
5451ddf
Response client tests completed
rodrigobr-msft Nov 3, 2025
c2cdd40
Beginning refactor of aiohttp runner
rodrigobr-msft Nov 3, 2025
7d91ef9
Unit test updates
rodrigobr-msft Nov 3, 2025
87610a5
Fixing issues in refactor
rodrigobr-msft Nov 3, 2025
ddfdd0b
Fixed TestIntegrationFromSample unit test
rodrigobr-msft Nov 3, 2025
dd0a87d
Another commit
rodrigobr-msft Nov 3, 2025
6a4e8ef
Reorganizing files
rodrigobr-msft Nov 3, 2025
7793790
Completed TestIntegrationFromServiceUrl unit tests
rodrigobr-msft Nov 3, 2025
3ebbd44
Reformatting with black
rodrigobr-msft Nov 3, 2025
a6681bf
Quickstart integration test beginning
rodrigobr-msft Nov 3, 2025
1a7264b
Draft of quickstart sample setup
rodrigobr-msft Nov 3, 2025
9ba4a43
Environment config connection
rodrigobr-msft Nov 3, 2025
fab4368
Renaming messaging endpoint to agent url
rodrigobr-msft Nov 4, 2025
a111155
Removing unnecessary files
rodrigobr-msft Nov 4, 2025
a2a1092
Fixing agent client payload sending
rodrigobr-msft Nov 4, 2025
ae8a286
First successful integration test
rodrigobr-msft Nov 4, 2025
9a5a6a8
Beginning foundational test cases
rodrigobr-msft Nov 4, 2025
aad011a
TypingIndicator test
rodrigobr-msft Nov 4, 2025
be0032a
Adding more test cases
rodrigobr-msft Nov 4, 2025
e3f4324
More foundational integration test cases
rodrigobr-msft Nov 4, 2025
a077eed
Reorganizing testing tools into package
rodrigobr-msft Nov 5, 2025
49161c3
Polished the testing framework package
rodrigobr-msft Nov 6, 2025
69d68d4
Adding verbose logging for results with benchmark tool
rodrigobr-msft Nov 6, 2025
3dc3efa
General cleanup
rodrigobr-msft Nov 6, 2025
054a3a2
Adding README
rodrigobr-msft Nov 6, 2025
8a5f22e
Revising README
rodrigobr-msft Nov 6, 2025
4b7c673
Formatting
rodrigobr-msft Nov 6, 2025
01f8f5a
Addressing PR comments
rodrigobr-msft Nov 6, 2025
9cccc1f
Merge branch 'main' of https://github.com/microsoft/Agents-for-python…
rodrigobr-msft Nov 6, 2025
8f87aff
Removing unused import
rodrigobr-msft Nov 6, 2025
e742e00
Update dev/microsoft-agents-testing/microsoft_agents/testing/sdk_conf…
rodrigobr-msft Nov 6, 2025
a6e305a
Update dev/microsoft-agents-testing/pyproject.toml
rodrigobr-msft Nov 6, 2025
c3877a3
Update dev/microsoft-agents-testing/microsoft_agents/testing/auth/gen…
rodrigobr-msft Nov 6, 2025
fb5b76d
Update dev/microsoft-agents-testing/microsoft_agents/testing/integrat…
rodrigobr-msft Nov 6, 2025
5eb9bfb
Removing unused code
rodrigobr-msft Nov 6, 2025
81b5d6b
Merge branch 'users/robrandao/integration' of https://github.com/micr…
rodrigobr-msft Nov 6, 2025
e451459
Adding field assertion helpers
rodrigobr-msft Nov 6, 2025
f241df8
Implementing field assertion types
rodrigobr-msft Nov 6, 2025
cb3c6aa
Adding data driven test foundation
rodrigobr-msft Nov 6, 2025
b8f3304
Separating assertions from checkers
rodrigobr-msft Nov 6, 2025
42b4ea1
Adjusting return values for check_activity with refactor
rodrigobr-msft Nov 6, 2025
2f79824
Fixing package name in pyproject.toml
rodrigobr-msft Nov 12, 2025
cfded79
Assertion test cases
rodrigobr-msft Nov 12, 2025
b6618b2
_parse_assertion unit tests
rodrigobr-msft Nov 12, 2025
1e8f19e
More assertion tests and fixes to data normalization logic
rodrigobr-msft Nov 12, 2025
d9eb5fa
Fixing more test cases with newest refactor
rodrigobr-msft Nov 12, 2025
f02b875
Fixing merge conflicts
rodrigobr-msft Nov 13, 2025
57b87eb
assert_activity tests
rodrigobr-msft Nov 13, 2025
6925093
Reorganizing tests
rodrigobr-msft Nov 13, 2025
6d55b29
Copyright comments
rodrigobr-msft Nov 13, 2025
6866f5d
DDT implementation outline
rodrigobr-msft Nov 13, 2025
1db2bf5
DataDrivenTest class
rodrigobr-msft Nov 13, 2025
e44a2da
select_activity implementation for assertions
rodrigobr-msft Nov 13, 2025
1cf561b
inverted assertions for quantifiers
rodrigobr-msft Nov 13, 2025
e651f92
ActivityAssertion class implementation
rodrigobr-msft Nov 13, 2025
ed7f2f1
DataDrivenTest implementation
rodrigobr-msft Nov 13, 2025
e88997e
Populate function for dictionaries
rodrigobr-msft Nov 13, 2025
0a48730
Populate tests
rodrigobr-msft Nov 14, 2025
2f96d88
Selector class implementation
rodrigobr-msft Nov 14, 2025
3a04fb5
Assertion tests completed for now
rodrigobr-msft Nov 14, 2025
31b2b99
Adding ActivityAssertion tests
rodrigobr-msft Nov 14, 2025
4df4788
DataDrivenTest implementation connected with default config
rodrigobr-msft Nov 14, 2025
0c195b1
More test cases and formatting
rodrigobr-msft Nov 14, 2025
7a79cc9
Data driven testing single test setup support
rodrigobr-msft Nov 14, 2025
f8c9166
Formatting
rodrigobr-msft Nov 14, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions dev/integration/data_driven_tests/basic_test.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
parent: ./defaults.yaml
description: A basic data driven test example
defaults:
input:
sleep:
assertion:
test:
- type: input
activity:
type: message
text: "Hello, World!"

- type: sleep
duration: 1

- type: assertion
quantifier: ONE
selector:
index: -1
quantifier: ONE
activity:
type: message
activity:
type: message
text: "Hello, World!"
10 changes: 10 additions & 0 deletions dev/integration/data_driven_tests/defaults.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
defaults:
all:
channel_id: "test_channel"
service_url: "http://localhost:3978"
locale: "en-US"
conversation_id: "test_conversation"
input:
user_id: "test_user"
output:
user_id: "test_bot"
2 changes: 2 additions & 0 deletions dev/integration/integration/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Microsoft 365 Agents SDK for Python Integration Testing Framework

Empty file.
Empty file.
16 changes: 16 additions & 0 deletions dev/integration/integration/integration/foundational/_common.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import json

from microsoft_agents.activity import Activity


def load_activity(channel: str, name: str) -> Activity:

with open(
"./dev/integration/src/tests/integration/foundational/activities/{}/{}.json".format(
channel, name
),
"r",
) as f:
activity = json.load(f)

return Activity.model_validate(activity)
141 changes: 141 additions & 0 deletions dev/integration/integration/integration/foundational/test_suite.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
import json
Copy link

Copilot AI Nov 14, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Syntax Error (in Python 3).

Copilot uses AI. Check for mistakes.
import pytest
import asyncio

from microsoft_agents.activity import (
ActivityTypes,
)

from src.core import integration, IntegrationFixtures, AiohttpEnvironment
from src.samples import QuickstartSample

from ._common import load_activity

DIRECTLINE = "directline"

@integration()
class TestFoundation(IntegrationFixtures):

def load_activity(self, activity_name) -> Activity:
return load_activity(DIRECTLINE, activity_name)

@pytest.mark.asyncio
async def test__send_activity__sends_hello_world__returns_hello_world(self, agent_client):
activity = load_activity(DIRECTLINE, "hello_world.json")
result = await agent_client.send_activity(activity)
assert result is not None
last = result[-1]
assert last.type == ActivityTypes.message
assert last.text.lower() == "you said: {activity.text}".lower()

@pytest.mark.asyncio
async def test__send_invoke__send_basic_invoke_activity__receive_invoke_response(self, agent_client):
activity = load_activity(DIRECTLINE, "basic_invoke.json")
result = await agent_client.send_activity(activity)
assert result
data = json.loads(result)
message = data.get("message", {})
assert "Invoke received." in message
assert "data" in data
assert data["parameters"] and len(data["parameters"]) > 0
assert "hi" in data["value"]

@pytest.mark.asyncio
async def test__send_activity__sends_message_activity_to_ac_submit__return_valid_response(self, agent_client):
activity = load_activity(DIRECTLINE, "ac_submit.json")
result = await agent_client.send_activity(activity)
assert result is not None
last = result[-1]
assert last.type == ActivityTypes.message
assert "doStuff" in last.text
assert "Action.Submit" in last.text
assert "hello" in last.text

@pytest.mark.asyncio
async def test__send_invoke_sends_invoke_activity_to_ac_execute__returns_valid_adaptive_card_invoke_response(self, agent_client):
activity = load_activity(DIRECTLINE, "ac_execute.json")
result = await agent_client.send_invoke(activity)

result = json.loads(result)

assert result.status == 200
assert result.value

assert "application/vnd.microsoft.card.adaptive" in result.type

activity_data = json.loads(activity.value)
assert activity_data.get("action")
user_text = activity_data.get("usertext")
assert user_text in result.value

@pytest.mark.asyncio
async def test__send_activity_sends_text__returns_poem(self, agent_client):
pass

@pytest.mark.asyncio
async def test__send_expected_replies_activity__sends_text__returns_poem(self, agent_client):
activity = self.load_activity("expected_replies.json")
result = await agent_client.send_expected_replies(activity)
last = result[-1]
assert last.type == ActivityTypes.message
assert "Apollo" in last.text
assert "\n" in last.text

@pytest.mark.asyncio
async def test__send_invoke__query_link__returns_text(self, agent_client):
activity = self.load_activity("query_link.json")
result = await agent_client.send_invoke(activity)
pass # TODO

@pytest.mark.asyncio
async def test__send_invoke__select_item__receive_item(self, agent_client):
activity = self.load_activity("select_item.json")
result = await agent_client.send_invoke(activity)
pass # TODO

@pytest.mark.asyncio
async def test__send_activity__conversation_update__returns_welcome_message(self, agent_client):
activity = self.load_activity("conversation_update.json")
result = await agent_client.send_activity(activity)
last = result[-1]
assert "Hello and Welcome!" in last.text

@pytest.mark.asyncio
async def test__send_activity__send_heart_message_reaction__returns_message_reaction_heart(self, agent_client):
activity = self.load_activity("message_reaction_heart.json")
result = await agent_client.send_activity(activity)
last = result[-1]
assert last.type == ActivityTypes.message
assert "Message Reaction Added: heart" in last.text

@pytest.mark.asyncio
async def test__send_activity__remove_heart_message_reaction__returns_message_reaction_heart(self, agent_client):
activity = self.load_activity
result = await agent_client.send_activity(activity)
last = result[-1]
assert last.type == ActivityTypes.message
assert "Message Reaction Removed: heart" in last.text

@pytest.mark.asyncio
async def test__send_expected_replies_activity__send_seattle_today_weather__returns_weather(self, agent_client):
activity = self.load_activity("expected_replies_seattle_weather.json")
result = await agent_client.send_expected_replies(activity)
last = result[-1]
assert last.type == ActivityTypes.message
assert last.attachments and len(last.attachments) > 0

adaptive_card = last.attachments.first()
assert adaptive_card
assert "application/vnd.microsoft.card.adaptive" == adaptive_card.content_type
assert adaptive_card.content

assert \
"�" in adaptive_card.content or \
"\\u00B0" in adaptive_card.content or \
f"Missing temperature inside adaptive card: {adaptive_card.content}" in adaptive_card.content

@pytest.mark.asyncio
async def test__send_activity__simulate_message_loop__expect_question_about_time_and_returns_weather(self, agent_client):
activities = self.load_activity("message_loop_1.json")
fresult = await agent_client.send_activity(activities[0])
assert
21 changes: 21 additions & 0 deletions dev/integration/integration/integration/test_quickstart.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# import pytest
# import asyncio

# from src.core import IntegrationFixtures, AiohttpEnvironment
# from src.samples import QuickstartSample

# class TestQuickstart(Integration):
# _sample_cls = QuickstartSample
# _environment_cls = AiohttpEnvironment

# @pytest.mark.asyncio
# async def test_welcome_message(self, agent_client, response_client):
# res = await agent_client.send_expect_replies("hi")
# await asyncio.sleep(1) # Wait for processing
# responses = await response_client.pop()

# assert len(responses) == 0

# first_non_typing = next((r for r in res if r.type != "typing"), None)
# assert first_non_typing is not None
# assert first_non_typing.text == "you said: hi"
1 change: 1 addition & 0 deletions dev/integration/integration/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
aioresponses
8 changes: 8 additions & 0 deletions dev/integration/test_basics.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from microsoft_agents.testing import DataDrivenTester


class TestBasics(DataDrivenTester):
_input_dir = "./data_driven_tests"

def test(self):
self._run_data_driven_test("input_file.json")
Empty file.
Original file line number Diff line number Diff line change
@@ -1,5 +1,20 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

from .sdk_config import SDKConfig

from .assertions import (
ActivityAssertion,
Selector,
AssertionQuantifier,
assert_activity,
assert_field,
check_activity,
check_activity_verbose,
check_field,
check_field_verbose,
FieldAssertionType,
)
from .auth import generate_token, generate_token_from_config

from .utils import populate_activity, get_host_and_port
Expand Down Expand Up @@ -27,4 +42,14 @@
"Integration",
"populate_activity",
"get_host_and_port",
"ActivityAssertion",
"Selector",
"AssertionQuantifier",
"assert_activity",
"assert_field",
"check_activity",
"check_activity_verbose",
"check_field",
"check_field_verbose",
"FieldAssertionType",
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License.

from .activity_assertion import ActivityAssertion
from .assertions import (
assert_activity,
assert_field,
)
from .check_activity import check_activity, check_activity_verbose
from .check_field import check_field, check_field_verbose
from .type_defs import FieldAssertionType, AssertionQuantifier, UNSET_FIELD
from .selector import Selector

__all__ = [
"ActivityAssertion",
"assert_activity",
"assert_field",
"check_activity",
"check_activity_verbose",
"check_field",
"check_field_verbose",
"FieldAssertionType",
"Selector",
"AssertionQuantifier",
"UNSET_FIELD",
]
Loading
Loading