Bird
Raised Fist0
Denoframework~15 mins

Mocking and stubbing in Deno - Deep Dive

Choose your learning style10 modes available
Overview - Mocking and stubbing
What is it?
Mocking and stubbing are techniques used in software testing to replace parts of a program with fake versions. These fake parts simulate real behavior so you can test how your code works without relying on external systems or complex dependencies. Mocking usually checks if certain actions happen, while stubbing provides preset responses to calls. Together, they help isolate the code under test and make tests faster and more reliable.
Why it matters
Without mocking and stubbing, tests would depend on real databases, APIs, or services, making them slow, flaky, or hard to run anywhere. This would slow down development and cause frustration when bugs hide in complex setups. Mocking and stubbing let developers test just their code’s logic quickly and safely, improving confidence and speed in building software.
Where it fits
Before learning mocking and stubbing, you should understand basic testing concepts like writing test cases and assertions in Deno. After mastering mocking and stubbing, you can explore advanced testing topics like integration testing, test coverage, and continuous integration pipelines.
Mental Model
Core Idea
Mocking and stubbing replace real parts of a program with controlled fake versions to test code behavior in isolation.
Think of it like...
Imagine testing a car’s radio without needing the whole car or electricity by using a pretend radio that acts like the real one but is easy to control and observe.
┌───────────────┐       ┌───────────────┐
│ Code under    │ calls │ Mock or Stub  │
│ test          │──────▶│ (Fake part)   │
└───────────────┘       └───────────────┘
       ▲                        │
       │                        ▼
┌───────────────┐       ┌───────────────┐
│ Real dependency│       │ Controlled    │
│ (Database, API)│       │ behavior or   │
└───────────────┘       │ preset data   │
                        └───────────────┘
Build-Up - 7 Steps
1
FoundationUnderstanding basic testing concepts
🤔
Concept: Learn what tests are and why we write them to check code correctness.
Testing means writing small programs called test cases that run your code with known inputs and check if the outputs match what you expect. In Deno, you write tests using the built-in test runner with simple functions and assertions.
Result
You can run tests that tell you if your code works as expected or if something is broken.
Understanding tests is the foundation for knowing why and how mocking and stubbing help make tests better.
2
FoundationIdentifying external dependencies in code
🤔
Concept: Recognize parts of your code that rely on outside systems like databases or APIs.
Look at your code and find where it calls external services or resources. These dependencies can slow tests or cause failures unrelated to your code’s logic.
Result
You know which parts of your code need to be replaced or faked during testing.
Knowing external dependencies helps you decide where mocking or stubbing is needed to isolate your tests.
3
IntermediateCreating stubs to provide preset responses
🤔Before reading on: do you think stubs can verify if a function was called, or only provide fixed responses? Commit to your answer.
Concept: Stubs replace real functions with fake ones that return fixed data to control test conditions.
In Deno, you can create a stub by writing a function that returns a fixed value instead of calling the real service. For example, if your code fetches user data, stub it to return a sample user object instantly.
Result
Tests run faster and predictably because the stub returns known data without delays or failures.
Understanding stubs lets you control test inputs precisely, making tests reliable and repeatable.
4
IntermediateUsing mocks to verify interactions
🤔Before reading on: do you think mocks only fake data, or can they also check if functions were called correctly? Commit to your answer.
Concept: Mocks replace real parts and record how they were used, letting tests check if expected calls happened.
In Deno, you can create a mock object with functions that track calls and arguments. After running your code, you assert that these functions were called the right number of times with correct data.
Result
You can test not just outputs but also if your code interacted correctly with dependencies.
Knowing mocks helps you test behavior and side effects, not just results.
5
IntermediateCombining mocks and stubs in tests
🤔
Concept: Use both mocks and stubs together to fully control and observe external parts during testing.
For example, stub a database call to return fixed data and mock a logger to check if error messages were logged. This combination isolates your code and verifies its reactions.
Result
Tests become comprehensive, checking both data flow and interactions.
Combining mocks and stubs gives you full control over test environments and behaviors.
6
AdvancedImplementing mocks and stubs with Deno’s testing tools
🤔Before reading on: do you think Deno has built-in support for mocks and stubs, or do you need external libraries? Commit to your answer.
Concept: Learn how to write mocks and stubs using Deno’s native features without extra libraries.
Deno’s standard library provides assertion functions and you can write simple mock/stub functions manually. For example, create a stub by replacing a module’s function with a custom one during tests using dependency injection or dynamic imports.
Result
You can write effective mocks and stubs using only Deno’s built-in tools, keeping tests simple and dependency-free.
Knowing how to mock and stub with native tools avoids extra dependencies and keeps tests lightweight.
7
ExpertAvoiding common pitfalls in mocking and stubbing
🤔Before reading on: do you think overusing mocks can make tests fragile or more reliable? Commit to your answer.
Concept: Understand the risks of excessive or improper mocking and how to balance test isolation with maintainability.
Over-mocking can cause tests to break when internal code changes, even if behavior is correct. It can hide real integration issues. Experts use mocks and stubs only where necessary and combine them with integration tests to catch real problems.
Result
Tests remain stable, meaningful, and maintainable over time.
Knowing when and how much to mock prevents fragile tests and ensures real-world reliability.
Under the Hood
Mocking and stubbing work by replacing references to real functions or objects with fake ones during test execution. In Deno, this can be done by passing fake implementations as parameters, using dynamic imports, or manually overriding functions. When the code under test calls these fakes, they return preset data or record calls instead of executing real logic. This isolates the test from external systems and controls behavior precisely.
Why designed this way?
These techniques were designed to solve the problem of testing code that depends on slow, unreliable, or unavailable external resources. By faking these parts, tests become fast, deterministic, and easier to write. Alternatives like full integration tests are slower and more complex, so mocking and stubbing provide a practical balance between speed and coverage.
┌───────────────┐       ┌───────────────┐       ┌───────────────┐
│ Test runner   │──────▶│ Code under    │──────▶│ Dependency    │
│ starts test   │       │ test          │       │ (real or fake)│
└───────────────┘       └───────────────┘       └───────────────┘
                                ▲                      ▲
                                │                      │
                                │                      │
                        ┌───────┴───────┐      ┌───────┴───────┐
                        │ Stub returns  │      │ Mock records  │
                        │ preset data   │      │ calls & args  │
                        └───────────────┘      └───────────────┘
Myth Busters - 4 Common Misconceptions
Quick: do you think mocks always provide fake data, or only check if functions were called? Commit to your answer.
Common Belief:Mocks are just fake data providers like stubs.
Tap to reveal reality
Reality:Mocks primarily record how functions are called to verify interactions, while stubs provide preset data without tracking calls.
Why it matters:Confusing mocks and stubs can lead to tests that miss checking important behaviors or produce misleading results.
Quick: do you think mocking external APIs is always the best way to test? Commit to your answer.
Common Belief:Mocking all external APIs is always best for testing.
Tap to reveal reality
Reality:While mocking speeds tests, over-mocking can hide integration problems and cause tests to pass even if real APIs break.
Why it matters:Relying only on mocks can give false confidence and cause bugs in production.
Quick: do you think you must use special libraries to mock or stub in Deno? Commit to your answer.
Common Belief:You need external libraries to mock or stub in Deno.
Tap to reveal reality
Reality:Deno’s built-in features and simple functions let you create mocks and stubs without extra libraries.
Why it matters:Believing you need libraries can slow learning and add unnecessary dependencies.
Quick: do you think mocks and stubs change your code’s logic? Commit to your answer.
Common Belief:Mocks and stubs alter the real logic of the code under test.
Tap to reveal reality
Reality:Mocks and stubs replace dependencies but do not change the code’s own logic; they isolate it for testing.
Why it matters:Misunderstanding this can cause confusion about test failures and code behavior.
Expert Zone
1
Mocks can be stateful, tracking call order and counts, which helps test complex interaction sequences.
2
Stubs can be dynamic, returning different data based on input, allowing more realistic test scenarios.
3
In Deno, careful use of dependency injection patterns simplifies mocking without modifying global state.
When NOT to use
Avoid mocking or stubbing when testing full system integration or performance, where real components must interact. Instead, use integration or end-to-end tests that run with actual dependencies.
Production Patterns
Professionals use mocks and stubs in unit tests to isolate logic, combined with integration tests for real dependencies. They apply dependency injection to swap real and fake parts easily and use test doubles sparingly to keep tests maintainable.
Connections
Dependency Injection
Mocks and stubs often rely on dependency injection to replace real parts with fakes.
Understanding dependency injection helps you design code that is easy to mock and stub, improving testability.
Isolation in Scientific Experiments
Both isolate one factor to study its effect without interference from others.
Knowing how scientists isolate variables helps grasp why mocking isolates code behavior for clear testing.
Simulation in Engineering
Mocks and stubs simulate parts of a system to test behavior without building the full system.
Seeing mocks as simulations clarifies their role in testing complex software systems efficiently.
Common Pitfalls
#1Over-mocking leading to fragile tests
Wrong approach:test('example', () => { const mockDb = { query: () => 'data' }; const mockLogger = { log: () => {} }; // many mocks for every small function // test breaks if internal calls change });
Correct approach:test('example', () => { const stubDb = { query: () => 'data' }; // mock only critical interactions // combine with integration tests });
Root cause:Misunderstanding that mocking every detail improves tests, instead of focusing on key interactions.
#2Confusing mocks and stubs usage
Wrong approach:const stub = () => { called = true; return 'data'; }; // test checks if stub was called, expecting mock behavior
Correct approach:const mock = { called: false, func: () => { mock.called = true; return 'data'; } }; // test asserts mock.called to verify interaction
Root cause:Not distinguishing that stubs provide data, mocks verify calls.
#3Trying to mock without dependency injection
Wrong approach:import realDb from './db.ts'; // directly calling realDb in tests without replacement
Correct approach:function fetchData(db = realDb) { return db.query(); } // pass stub or mock db in tests
Root cause:Not designing code to accept dependencies, making mocking impossible or awkward.
Key Takeaways
Mocking and stubbing let you replace real parts of your program with controlled fakes to test code in isolation.
Stubs provide fixed responses to control test inputs, while mocks record calls to verify interactions.
Using these techniques makes tests faster, more reliable, and easier to write by avoiding real external dependencies.
Deno supports mocking and stubbing with simple native features, so you don’t always need extra libraries.
Balancing mocking with integration tests prevents fragile tests and ensures your code works well in the real world.

Practice

(1/5)
1. What is the main purpose of mocking and stubbing in Deno testing?
easy
A. To speed up the execution of the entire program
B. To replace parts of code with fake versions for easier testing
C. To permanently change the behavior of functions in production
D. To automatically generate user interface components

Solution

  1. Step 1: Understand mocking and stubbing

    Mocking and stubbing are techniques used to replace parts of code with fake versions to isolate and test specific behaviors.
  2. Step 2: Identify the purpose in testing context

    They help test code without relying on real dependencies, making tests simpler and more reliable.
  3. Final Answer:

    To replace parts of code with fake versions for easier testing -> Option B
  4. Quick Check:

    Mocking purpose = Replace code parts [OK]
Hint: Mocking replaces code parts to isolate tests [OK]
Common Mistakes:
  • Thinking mocking speeds up the whole program
  • Believing mocks change production code permanently
  • Confusing mocking with UI generation
2. Which of the following is the correct way to import the stub function from Deno's standard testing library?
easy
A. import { stub } from "https://deno.land/std/testing/stub.ts";
B. import stub from "https://deno.land/std/testing/mock.ts";
C. import { stub } from "https://deno.land/std/testing/mock.ts";
D. import * as stub from "https://deno.land/std/testing/mock.ts";

Solution

  1. Step 1: Recall the correct import path and syntax

    The stub function is exported from "https://deno.land/std/testing/mock.ts" and must be imported using named import syntax.
  2. Step 2: Check each option

    import { stub } from "https://deno.land/std/testing/mock.ts"; uses named import from the correct path. import stub from "https://deno.land/std/testing/mock.ts"; uses default import which is incorrect. import { stub } from "https://deno.land/std/testing/stub.ts"; uses wrong file name. import * as stub from "https://deno.land/std/testing/mock.ts"; imports all as an object, not the function directly.
  3. Final Answer:

    import { stub } from "https://deno.land/std/testing/mock.ts"; -> Option C
  4. Quick Check:

    Correct import = named from mock.ts [OK]
Hint: Use named import from mock.ts for stub [OK]
Common Mistakes:
  • Using default import instead of named import
  • Wrong file path for stub
  • Importing everything instead of just stub
3. Given the following code snippet, what will be the output?
import { stub } from "https://deno.land/std/testing/mock.ts";

const obj = {
  greet() {
    return "Hello";
  }
};

const stubGreet = stub(obj, "greet", () => "Hi there!");
console.log(obj.greet());
stubGreet.restore();
console.log(obj.greet());
medium
A. "Hello" then "Hello"
B. "Hi there!" then "Hi there!"
C. Runtime error due to incorrect stub usage
D. "Hi there!" then "Hello"

Solution

  1. Step 1: Understand stub behavior on method

    The stub replaces obj.greet with a new function returning "Hi there!" temporarily.
  2. Step 2: Analyze console outputs

    First console.log calls stubbed method, outputting "Hi there!". After restore(), original method returns "Hello" on second log.
  3. Final Answer:

    "Hi there!" then "Hello" -> Option D
  4. Quick Check:

    Stub replaces then restores method [OK]
Hint: Stub changes method until restore is called [OK]
Common Mistakes:
  • Expecting original method output before restore
  • Thinking stub permanently changes method
  • Confusing stub with spy that tracks calls
4. What is the error in the following Deno test code using stub?
import { stub } from "https://deno.land/std/testing/mock.ts";

const obj = {
  value() {
    return 42;
  }
};

const stubValue = stub(obj, "val", () => 100);
console.log(obj.value());
stubValue.restore();
medium
A. Trying to stub a non-existent method 'val' on obj
B. Missing import statement for stub
C. restore() called before stub is created
D. Incorrect arrow function syntax in stub

Solution

  1. Step 1: Check stub target method name

    The stub tries to replace method named "val" but obj only has "value" method.
  2. Step 2: Understand stub behavior on invalid method

    Stubbing a non-existent method causes an error or does not work as expected.
  3. Final Answer:

    Trying to stub a non-existent method 'val' on obj -> Option A
  4. Quick Check:

    Stub method must exist on object [OK]
Hint: Stub only existing methods on objects [OK]
Common Mistakes:
  • Using wrong method name in stub
  • Forgetting to import stub
  • Calling restore too early
5. You want to test a function that calls fetchData() which normally fetches data from the internet. Using Deno's stub, how can you replace fetchData to return a fixed value { success: true } only during the test, and ensure the original fetchData is restored after the test?
hard
A. Use const stubFetch = stub(obj, "fetchData", () => ({ success: true })); then call stubFetch.restore() after test
B. Replace fetchData globally without restore, returning fixed value
C. Use stub(obj, "fetchData", async () => Promise.resolve({ success: true })); but forget to restore
D. Call stub(obj, "fetchData", () => { return true; }); without storing stub

Solution

  1. Step 1: Create a stub for fetchData returning fixed value

    Use stub on the object containing fetchData, replacing it with a function returning { success: true }.
  2. Step 2: Restore original method after test

    Store the stub in a variable and call restore() after the test to revert changes.
  3. Final Answer:

    Use const stubFetch = stub(obj, "fetchData", () => ({ success: true })); then call stubFetch.restore() after test -> Option A
  4. Quick Check:

    Stub with restore keeps tests clean [OK]
Hint: Always restore stub after test to keep original code [OK]
Common Mistakes:
  • Not restoring stub after test
  • Replacing globally without control
  • Returning wrong stub value type
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard