Mocking is a testing technique that replaces a dependency with a controlled substitute. Instead of calling a real database, cloud SDK client, HTTP endpoint, or clock, the code under test interacts with an object or function configured by the test. The test can supply responses, raise exceptions, and inspect calls. This isolates application logic from network availability, credentials, changing data, and service costs.
Strictly speaking, a mock verifies interactions, such as whether a method was called with the expected arguments. A stub supplies predetermined responses, while a fake provides a simplified working implementation. Testing frameworks often combine these capabilities, and engineers commonly use the word mocking for several kinds of dependency substitution. The important design decision is which boundary the test replaces and which behavior remains real.
For example, consider a Lambda function that validates an order and writes it to DynamoDB. Separate validation and order processing from the handler's event-parsing code, and pass a database client or repository into the processing function. A unit test can provide a mock repository, submit a valid order, and verify that the expected record was written once. Another test can submit an invalid order and verify that no write was attempted. Neither test requires a deployed Lambda function or an actual table.
Error paths are equally important. Configure the dependency to raise an appropriate throttling, timeout, or conditional-write exception, then check the application's response. If application code implements retries, a sequence of failures followed by success can exercise that logic. However, replacing an entire SDK method does not exercise the SDK's own internal retry behavior. Tests should distinguish application responsibilities from behavior implemented by the SDK or service.
Use a language-appropriate framework, such as Python's unittest.mock or JavaScript's Jest, to create substitutes and assertions. Tools such as Botocore Stubber can supply modeled SDK responses without sending requests. Inject dependencies explicitly where practical, or patch the reference used by the module under test. Reset mocks between tests, use realistic response structures, and avoid loading credentials or contacting metadata endpoints merely to construct a test dependency.
AWS SAM supports serverless development, but local invocation and mocking solve different problems. Unit tests can import application functions and run directly through a test runner without SAM or Docker. The sam local invoke command runs a Lambda function locally in a container using a supplied event. It does not automatically replace downstream AWS calls: those calls can still reach real services unless dependencies are substituted or explicitly configured otherwise. Likewise, a Lambda console test event invokes the deployed function; it does not make the invocation an isolated unit test.
Mocks trade fidelity for speed and control. They cannot prove that IAM permissions, resource policies, network access, event-source configuration, or actual service behavior are correct. Overly detailed interaction assertions can also make tests fragile during harmless refactoring. Prefer assertions about meaningful outcomes and important side effects, then complement mocked unit tests with integration tests against isolated cloud resources. This combination catches logic errors early while still validating the application's deployed behavior.