Skip to content

Add URL and payload validation to conversation client tests#265

Open
Copilot wants to merge 4 commits intomainfrom
copilot/improve-conversation-client-tests
Open

Add URL and payload validation to conversation client tests#265
Copilot wants to merge 4 commits intomainfrom
copilot/improve-conversation-client-tests

Conversation

Copy link
Contributor

Copilot AI commented Jan 28, 2026

Conversation client tests only verified non-null responses without validating HTTP requests. Tests now capture and assert on request methods, URLs, query parameters, and JSON payloads.

Changes

Added request_capture fixture

  • Captures HTTP requests during tests via mock transport
  • Exposes last_request property for validation
  • Returns standard Client instance compatible with existing APIs

Enhanced test assertions

  • HTTP method validation (GET, POST, PUT, DELETE)
  • Exact URL path validation including route parameters
  • Query parameter validation (e.g., continuationToken)
  • JSON payload validation for create/update operations (simplified to check 1 key field per test)
  • Authorization header validation for token-based authentication

Added token authorization test

  • New test_get_conversations_with_token validates Bearer tokens are properly sent in the Authorization header

Example

Before:

async def test_create_conversation(self, mock_http_client, mock_account):
    response = await client.create(params)
    assert response.id is not None

After:

async def test_create_conversation(self, request_capture, mock_account):
    response = await client.create(params)
    
    # Validate request
    request = request_capture._capture.last_request
    assert request.method == "POST"
    assert str(request.url) == "https://test.service.url/v3/conversations"
    
    payload = json.loads(request.content)
    assert payload["isGroup"] is True

Covers 10 methods across ConversationClient, ActivityOperations, and MemberOperations, plus token authorization.


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI and others added 2 commits January 28, 2026 20:48
Co-authored-by: heyitsaamir <48929123+heyitsaamir@users.noreply.github.com>
Co-authored-by: heyitsaamir <48929123+heyitsaamir@users.noreply.github.com>
Copilot AI changed the title [WIP] Improve conversation client tests for payload and URL Add URL and payload validation to conversation client tests Jan 28, 2026
Copilot AI requested a review from heyitsaamir January 28, 2026 20:55
Copy link
Collaborator

@heyitsaamir heyitsaamir left a comment

Choose a reason for hiding this comment

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

@copilot some feedback.

Co-authored-by: heyitsaamir <48929123+heyitsaamir@users.noreply.github.com>
Copilot AI requested a review from heyitsaamir January 28, 2026 21:04
@heyitsaamir heyitsaamir marked this pull request as ready for review January 28, 2026 21:06
Copilot AI review requested due to automatic review settings January 28, 2026 21:06
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR enhances conversation client tests by adding validation of HTTP request details (methods, URLs, query parameters, and JSON payloads) that were previously only checking for non-null responses. A new request_capture fixture is introduced to capture and inspect HTTP requests during testing.

Changes:

  • Added request_capture fixture in conftest.py to capture HTTP request details with mock transport
  • Enhanced 10 test methods to validate HTTP method, URL construction, query parameters, and request payloads
  • Added new test for Bearer token authorization header validation

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 5 comments.

File Description
packages/api/tests/conftest.py Added request_capture fixture with request capturing capabilities and mock response handling
packages/api/tests/unit/test_conversation_client.py Updated 10 test methods to use request_capture fixture and validate HTTP request details; added token authorization test

Comment on lines +88 to +90
from typing import Any

import httpx
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

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

Importing modules inside test functions is an anti-pattern. The typing.Any and httpx imports should be moved to the top of the file with the other imports, especially since httpx is already imported in conftest.py and used by the request_capture fixture.

Copilot uses AI. Check for mistakes.
Comment on lines +87 to +108
# Create request capture with the configured client
from typing import Any

import httpx

class RequestCapture:
def __init__(self):
self.requests: list[httpx.Request] = []

def handler(self, request: httpx.Request) -> httpx.Response:
self.requests.append(request)
response_data: Any = {
"conversations": [{"id": "test", "conversationType": "personal", "isGroup": False}],
"continuationToken": "token",
}
return httpx.Response(status_code=200, json=response_data, headers={"content-type": "application/json"})

@property
def last_request(self) -> httpx.Request | None:
return self.requests[-1] if self.requests else None

capture = RequestCapture()
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

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

This test has significant code duplication with the request_capture fixture defined in conftest.py. The RequestCapture class implementation (lines 92-106) duplicates the same class from the fixture. Instead of duplicating this code, the test should create the fixture with a custom Client that has the token configured, or extend the existing fixture to accept optional parameters.

Suggested change
# Create request capture with the configured client
from typing import Any
import httpx
class RequestCapture:
def __init__(self):
self.requests: list[httpx.Request] = []
def handler(self, request: httpx.Request) -> httpx.Response:
self.requests.append(request)
response_data: Any = {
"conversations": [{"id": "test", "conversationType": "personal", "isGroup": False}],
"continuationToken": "token",
}
return httpx.Response(status_code=200, json=response_data, headers={"content-type": "application/json"})
@property
def last_request(self) -> httpx.Request | None:
return self.requests[-1] if self.requests else None
capture = RequestCapture()
# Create request capture with the configured client using shared helper from conftest
import httpx
import conftest
capture = conftest.RequestCapture()

Copilot uses AI. Check for mistakes.

capture = RequestCapture()
transport = httpx.MockTransport(capture.handler)
from microsoft_teams.common.http import Client
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

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

The import statement is placed after several lines of code in the test function. This violates PEP 8 style guidelines where imports should be at the top of the file. Move this import to the top of the file.

Copilot uses AI. Check for mistakes.
assert str(last_request.url) == "https://test.service.url/v3/conversations"

# Validate request payload
payload = json.loads(last_request.content.decode("utf-8"))
Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

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

The .decode("utf-8") call is unnecessary here. The json.loads() function can accept bytes directly in Python 3.6+, so this can be simplified to json.loads(last_request.content). This applies to all similar instances in this file (lines 156, 207, 234, 261).

Suggested change
payload = json.loads(last_request.content.decode("utf-8"))
payload = json.loads(last_request.content)

Copilot uses AI. Check for mistakes.
Comment on lines +244 to +305
if "GetAadTokens" in str(request.url):
response_data = {
"https://graph.microsoft.com": {
"connectionName": "test_connection",
"token": "mock_graph_token_123",
"expiration": "2024-12-01T12:00:00Z",
},
}
elif "/conversations/" in str(request.url) and str(request.url).endswith("/members"):
response_data = [
{
"id": "mock_member_id",
"name": "Mock Member",
"objectId": "mock_object_id",
}
]
elif "/conversations/" in str(request.url) and "/members/" in str(request.url) and request.method == "GET":
response_data = {
"id": "mock_member_id",
"name": "Mock Member",
"objectId": "mock_object_id",
}
elif "/conversations" in str(request.url) and request.method == "GET":
response_data = {
"conversations": [
{
"id": "mock_conversation_id",
"conversationType": "personal",
"isGroup": True,
}
],
"continuationToken": "mock_continuation_token",
}
elif "/conversations" in str(request.url) and request.method == "POST":
response_data = {
"id": "mock_conversation_id",
"type": "message",
"activityId": "mock_activity_id",
"serviceUrl": "https://mock.service.url",
}
elif "/activities" in str(request.url):
if request.method == "POST":
response_data = {
"id": "mock_activity_id",
"type": "message",
"text": "Mock activity response",
}
elif request.method == "PUT":
response_data = {
"id": "mock_activity_id",
"type": "message",
"text": "Updated mock activity",
}
elif request.method == "GET":
response_data = [
{
"id": "mock_member_id",
"name": "Mock Member",
"objectId": "mock_object_id",
}
]

Copy link

Copilot AI Jan 28, 2026

Choose a reason for hiding this comment

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

The request_capture fixture duplicates response handling logic that already exists in the mock_transport fixture. Lines 244-304 in request_capture replicate the same endpoint matching and response generation as lines 46-198 in mock_transport. This duplication creates a maintenance burden where changes to mock responses must be made in two places. Consider refactoring to extract the response generation logic into a shared function that both fixtures can use, or make request_capture extend mock_transport instead of reimplementing it.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants