0

I'm testing a controller that has a call to a class that works like a Model.

const getAllProducts = (req, res) => {
    const products = new ProductModel().getAll();

    res.status(200)
    res.send(products)
}
class ProductModel {
    constructor(name, brand) {
        this.id = null;
        this.name = name;
        this.brand = brand;
    }

    getAll() {
        const rawData = fs.readFileSync('./products.json');
        const products = JSON.parse(rawData);

        return products;
    }
}

The thing is, I want to test the controller by mocking the model so it does not need to be called (or maybe I should mock only the fs part, not sure).

I saw a lot of stuff related to mocking functions inside functions (using spyOn and jest.mock) but nothing with a class.

1 Answer 1

2

In general, you need to mock/stub a direct dependency on the method being tested. For your case, the getAllProducts function is under-tested, so you need to mock getAll method of ProductModel class.

E.g.

controller.js:

import { ProductModel } from './productModel';

export const getAllProducts = (req, res) => {
  const products = new ProductModel('github', 'reddit').getAll();

  res.status(200);
  res.send(products);
};

productModel.js:

export class ProductModel {
  constructor(name, brand) {
    this.id = null;
    this.name = name;
    this.brand = brand;
  }

  getAll() {
    const rawData = fs.readFileSync('./products.json');
    const products = JSON.parse(rawData);

    return products;
  }
}

controller.test.js:

import { getAllProducts } from './controller';
import { ProductModel } from './productModel';

describe('61966593', () => {
  it('should pass', () => {
    const mData = { data: [1, 2, 3] };
    const getAllSpy = jest.spyOn(ProductModel.prototype, 'getAll').mockReturnValueOnce(mData);
    const mReq = {};
    const mRes = { status: jest.fn().mockReturnThis(), send: jest.fn() };
    getAllProducts(mReq, mRes);
    expect(getAllSpy).toBeCalledTimes(1);
    expect(mRes.status).toBeCalledWith(200);
    expect(mRes.send).toBeCalledWith({ data: [1, 2, 3] });
    getAllSpy.mockRestore();
  });
});

The outcome for the unit test:

 PASS  stackoverflow/61966593/controller.test.js (9.078s)
  61966593
    ✓ should pass (4ms)

-----------------|---------|----------|---------|---------|-------------------
File             | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-----------------|---------|----------|---------|---------|-------------------
All files        |      80 |      100 |      75 |   78.57 |                   
 controller.js   |     100 |      100 |     100 |     100 |                   
 productModel.js |      70 |      100 |   66.67 |   66.67 | 9-12              
-----------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        10.273s
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.