Welcome to Chapter 9! This is the final chapter of our testing tutorial series.
In the previous chapter, reset_event_state, we learned how to reset the "scoreboard" (counters and IDs) of the CrewAI event system. We ensured that every test starts with Event ID #1.
However, resetting the score isn't enough. We also need to clear out the audience.
The Use Case: Imagine you are testing a notification system in CrewAI.
The Reason: The "rule" (Handler) you created in Test A was registered to a global system (the Event Bus). Even though Test A is over, the Event Bus still remembers that rule. The "listener" is still sitting in the room, waiting for events.
The Solution: We need a bouncer. After every single party (test), the bouncer needs to clear the room, forcing all listeners to leave. This ensures Test B starts with an empty room.
cleanup_event_handlers?
This is a function-scoped fixture in pytest.
Here is the lifecycle of a test using this fixture.
Let's look at conftest.py. This implementation deals with Global State and Thread Safety, but we can break it down into simple steps.
@pytest.fixture(autouse=True, scope="function")
def cleanup_event_handlers() -> Generator[None, Any, None]:
"""Clean up event bus handlers after each test."""
# 1. Yield control immediately.
# We don't need to do anything BEFORE the test.
yield
autouse=True: Just like the previous chapter, this runs automatically. You don't need to ask for it.yield: This is the dividing line. Everything above yield happens before the test. Everything below happens after. Since we only care about cleaning up the mess after, we yield immediately.After the test finishes, we need to find the mess.
try:
# 2. Import the global event bus
# This is where the handlers are hiding.
from crewai.events.event_bus import crewai_event_bus
crewai_event_bus: This is a Singleton (a variable that is shared across the entire application). This is where the pollution lives.CrewAI supports running agents in parallel (using threads). Because of this, we have to be careful not to delete a list while another thread is trying to read it.
# 3. Lock the bus so no one else touches it
with crewai_event_bus._rwlock.w_locked():
# 4. Clear the Synchronous handlers
crewai_event_bus._sync_handlers.clear()
# 5. Clear the Asynchronous handlers
crewai_event_bus._async_handlers.clear()
_rwlock.w_locked(): This stands for "Read-Write Lock (Write Locked)". It's like putting a "Cleaning in Progress" sign on the door and locking it. It ensures no background threads crash because we deleted their data..clear(): This empties the Python list. It deletes every listener inside it.Finally, we wrap it in a try-catch block to ensure the test suite doesn't crash if something goes wrong during cleanup.
except Exception:
# If cleanup fails, don't fail the test
pass
Congratulations! You have completed the entire tutorial on the crewAI testing infrastructure.
Let's recap the journey we took to build a robust, professional testing environment:
With these 9 tools working together in conftest.py, you can now write tests for AI Agents that are fast, cheap, secure, and reliable.
Happy Testing!
Generated by Code IQ