Welcome to Chapter 2!
In the previous chapter, setup_test_environment, we learned how to create a clean, isolated "sandbox" for our tests so they don't mess up our local files.
Now that our workspace is clean, we face a new problem: External Networks.
The Use Case: You are testing a CrewAI agent that uses OpenAI's GPT-4 to write a poem.
The Solution: VCR.py We use a tool called VCR (Video Cassette Recorder).
The vcr_config concept we are discussing today is the Settings Menu for this recorder. It tells the recorder where to save the tapes and how to handle sensitive data like API keys.
vcr_config?
In our codebase, vcr_config is a module-scoped fixture.
Let's look at how pytest-vcr (the plugin we use) asks for instructions.
Let's look at conftest.py to see how this configuration is built. We will break it down into small steps.
@pytest.fixture(scope="module")
def vcr_config(vcr_cassette_dir: str) -> dict[str, Any]:
"""Configure VCR with organized cassette storage."""
# Logic starts here...
@pytest.fixture(scope="module"): This config is calculated once for every test file.vcr_cassette_dir: Note that this function asks for another fixture as an input. This is dependency injection! We will learn about vcr_cassette_dir in Chapter 3: vcr_cassette_dir.Inside the function, we start building the dictionary.
config = {
"cassette_library_dir": vcr_cassette_dir,
"record_mode": os.getenv("PYTEST_VCR_RECORD_MODE", "once"),
"match_on": ["method", "scheme", "host", "port", "path"],
# ... more settings ...
}
cassette_library_dir: The folder path where the recordings live.record_mode: Usually set to "once".match_on: How does VCR know if a request matches a recording? It checks if the HTTP Method (GET/POST), the Host (openai.com), and the Path (/v1/chat/completions) are identical.
We cannot save raw requests because they contain your private sk-proj-... OpenAI keys.
"filter_headers": [(k, v) for k, v in HEADERS_TO_FILTER.items()],
"before_record_request": _filter_request_headers,
"before_record_response": _filter_response_headers,
filter_headers: A simple list of headers to scrub. We define these in HEADERS_TO_FILTER.before_record_request: A function that runs before writing a request to disk. We use _filter_request_headers (Chapter 5) to clean the data.before_record_response: A function that runs before writing the server's response to disk. We use _filter_response_headers (Chapter 6).Finally, we have a special check for when the code runs on GitHub Actions (the cloud).
if os.getenv("GITHUB_ACTIONS") == "true":
config["record_mode"] = "none"
return config
GITHUB_ACTIONS: If we are running in the cloud, we don't have API keys set up.record_mode = "none": This tells VCR: "Only replay tapes. If a test tries to make a new network request, crash immediately." This prevents tests from silently failing or hanging.
When you write a test in CrewAI, you don't call vcr_config directly. pytest-vcr finds this fixture automatically.
Example of what vcr_config returns:
{
"cassette_library_dir": "/path/to/crewai/tests/cassettes/llms",
"record_mode": "once",
"filter_headers": [
["authorization", "AUTHORIZATION-XXX"],
["api-key", "X-API-KEY-XXX"]
],
"match_on": ["method", "scheme", "host", "port", "path"]
}
Because of this configuration:
XXX.In this chapter, we learned:
vcr_config is the master settings file for our network recorder.
But waitβhow does it know where to put those cassette files? We saw a variable called vcr_cassette_dir passed into our config. In the next chapter, we will see how that path is calculated dynamically to keep our project organized.
Next Chapter: vcr_cassette_dir
Generated by Code IQ