Skip to content
Santekno.com | Tech Tutorials and Trends
EN
📖 0%
13 Aug 2025 · 6 min read ·Article 44 / 125
Go

44 Mocking the Database to Test Resolvers

IH
Ihsan Arif
Writer at Santekno · Backend Engineer

44 Mocking the Database to Test Resolvers: A Complete Guide with Examples and Diagrams

As engineers, we know that testing is one of the most important stages in an application’s development lifecycle. When we talk about modern architectures like GraphQL or REST, the resolver layer (whether it’s in a Node.js backend or some other framework) plays a vital role as the bridge between business logic and the database. The problem is, testing resolvers is often a hassle because you have to manage database dependencies. This is exactly where the concept of mocking the database becomes incredibly powerful.

In this article, I’ll cover “44 Mocking the Database to Test Resolvers”, starting from an introduction, then strategies, implementations with various popular tools, and finally real code simulations. The goal is to give you a comprehensive guide you can apply directly when writing unit and integration tests for resolvers in your own project.


Why Mock the Database for Resolvers?

The Real Problem

Ideally, unit tests should be deterministic, fast, and independent of external systems. If every time you test a resolver you have to query a real database, the testing process can become slow, the data inconsistent, and the debugging painful.

For example, say you have a GraphQL resolver like this:

js
1const resolvers = {
2  Query: {
3    user: async (_, { id }, { dataSources }) => {
4      return dataSources.userAPI.getUserById(id);
5    },
6  }
7};

If userAPI actually calls the database, what happens when your test data has changed? Or when the database is down? That’s where mocking the database becomes the solution.


44 Ways to Mock a Database

1. Manually Mock the Data Source (No Library)

The simplest approach is to directly override the function that accesses the DB and replace it with one that returns dummy data.

js
 1const mockUser = { id: 1, name: 'John Doe' };
 2
 3const dataSources = {
 4  userAPI: {
 5    getUserById: jest.fn().mockReturnValue(mockUser),
 6  },
 7};
 8
 9test('should fetch user from mocked database', async () => {
10  const response = await resolvers.Query.user(null, { id: 1 }, { dataSources });
11  expect(response).toEqual(mockUser);
12});

2. Using the Jest Library (Mocking and Spying)

Jest is extremely powerful for mocking database functions and is indeed widely used in the JavaScript/TypeScript ecosystem.

js
1jest.mock('../db', () => ({
2  getUserById: jest.fn().mockResolvedValue({ id: 1, name: "Jane Doe" }),
3}));

3. In-Memory Databases (SQLite, MongoMemoryServer)

If you need integration tests but don’t want to connect to a real DB, use an in-memory version of the database.

js
 1const { MongoMemoryServer } = require('mongodb-memory-server');
 2const mongoose = require('mongoose');
 3
 4let mongoServer;
 5
 6beforeAll(async () => {
 7  mongoServer = await MongoMemoryServer.create();
 8  const uri = mongoServer.getUri();
 9  await mongoose.connect(uri);
10});
11
12afterAll(async () => {
13  await mongoose.connection.close();
14  await mongoServer.stop();
15});

4. Database Mocking Libraries

There are plenty of ready-to-use third-party libraries for mocking databases, such as:

LibraryLanguageDB SupportUse Case
jest-mock-extendedJS/TSAnyUnit test
mock-knexJS/TSKnex (SQL)Unit test
sequelize-mockJS/TSSequelize (SQL)Unit test
sinonJS/TSAnyGeneral mock
testcontainersJS/TSAnyIntegration
sqlmockGoSQLUnit test
pytest-mockPythonAnyGeneral mock

Simulation: Mocking the Database for a GraphQL Resolver

Let’s take a concrete example. Imagine a Blog application built with GraphQL, with a getPost(id) resolver that fetches a post from the database. Here’s a diagram of the test flow using Mermaid:

MERMAID
flowchart TD
    A[Test Call getPost(id)] --> B[Resolver getPost]
    B --> C[DataSource: postAPI]
    C --> D[Mocked DB Function]
    D --> E[Return Mocked Data]
    B --> F[Response to Test]

1. Resolver Structure

js
1// postResolver.js
2const resolvers = {
3  Query: {
4    post: async (_, { id }, { dataSources }) => {
5      return dataSources.postAPI.getPostById(id);
6    }
7  }
8};

2. Mock postAPI

We set up a mock function, for example with Jest:

js
 1// postResolver.test.js
 2const resolvers = require('./postResolver');
 3
 4const mockPost = {
 5  id: "post-44",
 6  title: "Mocking Database untuk Test Resolver",
 7  content: "Panduan lengkap mengenal dan menggunakan mocking database."
 8};
 9
10const dataSources = {
11  postAPI: {
12    getPostById: jest.fn().mockResolvedValue(mockPost)
13  }
14};
15
16test('should return mocked post data', async () => {
17  const post = await resolvers.Query.post(null, { id: 'post-44' }, { dataSources });
18  expect(post).toEqual(mockPost);
19  expect(dataSources.postAPI.getPostById).toHaveBeenCalledWith('post-44');
20});

The output:

text
1PASS  ./postResolver.test.js
2✓ should return mocked post data (5 ms)

3. Test Simulation Table

InputData Source MethodData from Mock?Returned Result
id: ‘44’postAPI.getPostById(‘44’)Yes{id: ‘44’, …}
id: ‘99’postAPI.getPostById(‘99’)Yesundefined/null

44 Mocking Techniques Worth Trying

As engineers, reaching “44 Database Mocks” doesn’t mean there are literally 44 of them; it’s a philosophy that mocking is highly varied and rich in features. Here are a few popular ‘shortcuts’:

  1. Manually override a property on the database connection object.
  2. Use dependency injection to swap out the DB instance.
  3. Use environment variables so tests run against an in-memory DB.
  4. Jest.fn() or sinon.stub().
  5. Test doubles on DB functions using a library like ts-mockito.
  6. Use an ORM mock (sequelize-mock, a TypeORM fake connection).
  7. Auto-mock DB code using Jest/Babel facilities.
  8. Inline mock implementations within the resolver test.
  9. Use-case-based mocks (testing failure/success scenarios). 10-44. Combinations of all the techniques above (different parameters, invalid cases, async/await, error handling, and so on).

Practical Tips

  • Focus on isolation: Make sure the resolver never actually touches an external service.
  • Combine mock and spy: Use a spy to verify the interaction with the mock.
  • Test the error path too: Mock the DB function to throw an error, then test whether the resolver handles the error correctly.
  • For integration tests, use an in-memory or container DB (Testcontainers).

Conclusion

Mocking the database to test resolvers is a crucial part of keeping the engineering process robust, reliable, and developer-friendly. By understanding the various methods and tools for mocking, you can write tests that are more maintainable and scalable.

Go ahead and explore the approaches above, adapt them to your team’s needs, and don’t forget to keep up with the latest tools. Remember, our goal isn’t simply to write tests, but to write tests that genuinely protect the quality of the application. Happy testing! 🚀


Danger
Do you have a go-to database mocking technique that isn’t covered above? Share it in the comments!

Related Articles

💬 Comments