Skip to content

Conversation

i2y
Copy link
Contributor

@i2y i2y commented Oct 4, 2025

This PR adds comprehensive testing guide with ASGI/WSGI examples for services, clients, and interceptors.

i2y added 2 commits October 4, 2025 14:18
Signed-off-by: i2y <[email protected]>
@i2y i2y force-pushed the docs/add-testing-guide branch from 1f96395 to a29ee46 Compare October 5, 2025 12:18
@i2y i2y marked this pull request as ready for review October 13, 2025 08:20
Copy link
Member

@stefanvanburen stefanvanburen left a comment

Choose a reason for hiding this comment

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

looks good to me — we're being pretty pytest-specific in this doc, but I think that's reasonable given how much the ecosystem seems to prefer it over unittest

docs/testing.md Outdated
Comment on lines 527 to 533
method_name = ctx.method().name
self.requests.append(method_name)
return method_name

async def on_end(self, token, ctx):
# token is the value returned from on_start
pass
Copy link
Member

Choose a reason for hiding this comment

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

do we need to return the method_name / have the comment if we just check self.requests? up to you if you want to keep this in (similar comment for WSGI)

Copy link
Collaborator

Choose a reason for hiding this comment

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

Agree that along the lines of above comments, it's best if we show how to test something real since users will be reading this for advice on that. This LoggingInterceptor doesn't actually log - to make it a testable real interceptor, we'd probably pass in a Logger and mock it or similar. Alternatively, auth interceptor may be easier to demonstrate here

Copy link
Collaborator

@anuraaga anuraaga left a comment

Choose a reason for hiding this comment

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

I agree pytest is a de-facto standard and don't think we need to avoid it in the examples. However, I've left some comments in that we probably should minimize actually documenting pytest itself - one reason is that it does end up looking like we basically require pytest for testing connect code which isn't the case.

Perhaps in the very first section Recommended approach: In-memory testing we can add a code snippet with no test infrastructure at all, documenting the most important point of the doc, using the httpx transports to connect a client and server without an app server.

import httpx
from greet_connect import GreetASGIApplication
from server import Greeter

app = GreetASGIApplication(Greeter())
async with httpx.AsyncClient(
  transport=httpx.ASGITransport(app=app),
            base_url="http://test"
        ) as session:
          client = GreetServiceClient("http://test", session=session) # URL is ignored
          response = client.greet(GreetRequest(name="Alice"))
print(response.greeting)

Then add some examples wiring it up to pytest, including some basic example of fixture. But I'd recommend

  • Keeping "general usage of connect" as much as possible in other docs (we can add what's missing there that we have in this PR)
  • Minimizing "general usage of pytest" as much as possible. In fact, instead of having many examples of pytest usage, we could instead have our basic example covered in two forms, pytest and unittest

How does that sound?

docs/testing.md Outdated
from greet.v1.greet_connect import GreetService, GreetServiceASGIApplication, GreetServiceClient
from greet.v1.greet_pb2 import GreetRequest, GreetResponse

class TestGreetService(GreetService):
Copy link
Collaborator

Choose a reason for hiding this comment

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

For the section about testing services, I think we wouldn't have names like TestService - we should be testing the real code here.

I think we can do something like

Testing the service we created in the [Getting Started](./getting-started) guide may look like this:

from greet_connect import GreetASGIApplication
from server import Greeter

any real test will be importing the service, not having it defined in the same file

docs/testing.md Outdated
@pytest.mark.asyncio
async def test_greet():
# Create the ASGI application
app = GreetServiceASGIApplication(TestGreetService())
Copy link
Collaborator

Choose a reason for hiding this comment

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

We can't show it clearly with our example services, we could consider something like # Initialize your service with mock dependencies as needed. Though maybe we can leave "general testing" advice out of the doc

docs/testing.md Outdated
assert response.greeting == "Hello, Alice!"

@pytest.mark.asyncio
async def test_greet_multiple_names(greet_client):
Copy link
Collaborator

Choose a reason for hiding this comment

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

There doesn't seem to be multiple names. How about empty_name and use empty string?

docs/testing.md Outdated
- Follows pytest best practices
- Matches the pattern used in connect-python's own test suite

### Testing error handling
Copy link
Collaborator

Choose a reason for hiding this comment

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

After writing below comments, I also thought this overlaps well with errors.md.


@pytest.mark.asyncio
async def test_client_error_handling():
class TestGreetService(GreetService):
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is it worth something like # It can be convenient to use a mock such as with pytest mocker?

docs/testing.md Outdated
Comment on lines 527 to 533
method_name = ctx.method().name
self.requests.append(method_name)
return method_name

async def on_end(self, token, ctx):
# token is the value returned from on_start
pass
Copy link
Collaborator

Choose a reason for hiding this comment

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

Agree that along the lines of above comments, it's best if we show how to test something real since users will be reading this for advice on that. This LoggingInterceptor doesn't actually log - to make it a testable real interceptor, we'd probably pass in a Logger and mock it or similar. Alternatively, auth interceptor may be easier to demonstrate here

docs/testing.md Outdated

### Project structure

Organize your tests in a `test/` directory at the root of your project:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Actually this is something I forgot when reorganizing for this repo - AFAIK, tests is the default for pytest and doesn't require configuration, that's what we should use here.

That being said, this whole section seems more like docs on how to use pytest, rather than testing connect. Maybe we can remove it?

docs/testing.md Outdated
async def greet(self, request, ctx):
# Check for authorization header
auth = ctx.request_headers().get("authorization")
if not auth or not auth.startswith("Bearer "):
Copy link
Collaborator

Choose a reason for hiding this comment

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

If we update the interceptor example, we can remove this one, which is good since I think it's very far from any real life service

i2y and others added 8 commits October 19, 2025 13:30
Co-authored-by: Anuraag (Rag) Agrawal <[email protected]>
Signed-off-by: Yasushi Itoh <[email protected]>
Co-authored-by: Anuraag (Rag) Agrawal <[email protected]>
Signed-off-by: Yasushi Itoh <[email protected]>
Signed-off-by: i2y <[email protected]>
Signed-off-by: i2y <[email protected]>
Signed-off-by: i2y <[email protected]>
Signed-off-by: i2y <[email protected]>
Signed-off-by: i2y <[email protected]>
@i2y
Copy link
Contributor Author

i2y commented Oct 19, 2025

@anuraaga @stefanvanburen
Thanks! I've addressed your comments. Could you please review this PR again?

Copy link
Collaborator

@anuraaga anuraaga left a comment

Choose a reason for hiding this comment

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

Looks much nicer, thanks!

docs/testing.md Outdated

## Setup

Install httpx for testing connect-python services and clients:
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't know if we need this, won't it always be installed as a dependency of connect-python?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks for catching that! Fixed in 58d6653.

Signed-off-by: i2y <[email protected]>
@i2y i2y merged commit 386bddc into main Oct 21, 2025
23 checks passed
@i2y i2y deleted the docs/add-testing-guide branch October 21, 2025 03:36
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.

3 participants