Learn the concept
A fake replaces a dependency with a simpler implementation. It is useful when the real dependency is slow, expensive, unavailable, or nondeterministic. A fake model can return predetermined outputs while you test validation and workflow logic.
An integration test checks that components fit together, such as a parser writing to a real local SQLite database. Keep both levels: fakes cannot prove the real adapter uses the provider contract correctly. Label what each test actually verifies.
Inject clocks, random generators, and clients where needed for deterministic tests. Use temporary directories and fresh databases to isolate state. Include failures in fixtures; otherwise your test suite may exercise every successful branch and none of the recovery behavior.
Run and inspect
class FakeModel:
def __init__(self, response): self.response = response
def generate(self, prompt): return self.response
def answer(client, question):
if not question.strip(): raise ValueError("Question required")
return client.generate(question)
assert answer(FakeModel("fixture"), "Hello") == "fixture"
Your exercise
Create one unit test using a fake reader and one integration test reading a temporary file. Make the reader fail in a third test.
Check your understanding
Your report states that fake-model tests validate application behavior, not real model answer quality.