navig8tr
navig8tr

Reputation: 1854

Unit test Mysql without connecting to database with NodeJS

I have a Conn class that is used to connect to a MySQL database using AWS IAM Authentication and run a query. I have the class written and it is working correctly, but I'm having a lot of difficulties trying to test it without hitting a database.

Here is the Conn Class:

const AWS = require('aws-sdk');
const mysql = require("mysql2/promise");

class Conn {
    constructor(options = {}) {
        this.options = options;
    }

    async getPool() {
        return mysql.createPool(this.options);
    }

    setToken () {
        this.signer = new AWS.RDS.Signer({
            region: 'us-east-1', // example: us-east-2
            hostname: this.options.host,
            port: 3306,
            username: this.options.user
        });

        this.token = this.signer.getAuthToken({
            username: this.options.user
        });
    }

    async setConnection () {
        this.dbOptions = {
            host     : this.options.host,
            user     : this.options.user,
            ssl: 'Amazon RDS',
            password: this.token,
            authPlugins: {
                mysql_clear_password: () => () => Buffer.from(this.token + '\0')
            }
        };

        this.pool = await this.getPool(this.dbOptions);
        this.conn = await this.pool.getConnection();
    }

    async executeQuery () {
        this.dbResult = await this.conn.query("select 1 + 1 as solution");
        this.conn.release();
    }
}

module.exports = {
    Conn: Conn
}

And here I'm trying to test the Conn.executeQuery function using sinon:

const { handler } = require("../src/conn");
const sinon = require("sinon");
const {expect: expects} = require("chai");
const connection = require('../src/conn');

describe("conn", () => {
    afterEach(() => {
        sinon.restore();
    });
    it("should test conn.executeQuery", async () => {
        const connStub = { query: sinon.stub().resolves({ rowCount: 1 }), release: sinon.stub() };
        const poolStub = { getConnection: sinon.stub().resolves(connStub) };
        const pool = {getPool: sinon.stub().resolves(poolStub)};
        const conn = new connection.Conn();
        await conn.setConnection();
        const actual = await conn.executeQuery()
        expects(actual).to.be.eql({ rowCount: 1 });
        sinon.assert.calledWith(connStub.query, "select 1 + 1 as solution");
        sinon.assert.calledOnce(connStub.release);
    });
});

Unfortunately, all this code produces is errors, such as

Error: connect ECONNREFUSED 127.0.0.1:3306

How can I test the Conn.executeQuery function using sinon and not hit a database?

Upvotes: 1

Views: 1397

Answers (1)

Lin Du
Lin Du

Reputation: 102587

unit test solution:

Conn.js:

const mysql = require('mysql2/promise');

class Conn {
  constructor(options = {}) {
    this.options = options;
  }

  async getPool() {
    return mysql.createPool(this.options);
  }

  async setConnection() {
    this.dbOptions = {
      host: this.options.host,
      user: this.options.user,
      ssl: 'Amazon RDS',
      password: this.token,
      authPlugins: {
        mysql_clear_password: () => () => Buffer.from(this.token + '\0'),
      },
    };

    this.pool = await this.getPool(this.dbOptions);
    this.conn = await this.pool.getConnection();
  }

  async executeQuery() {
    this.dbResult = await this.conn.query('select 1 + 1 as solution');
    this.conn.release();
  }
}

module.exports = { Conn };

Conn.test.js:

const { Conn } = require('./Conn');
const sinon = require('sinon');
const mysql = require('mysql2/promise');

describe('64112250', () => {
  afterEach(() => {
    sinon.restore();
  });
  it('should test conn.executeQuery', async () => {
    const poolStub = {
      getConnection: sinon.stub().returnsThis(),
      query: sinon.stub().returnsThis(),
      release: sinon.stub(),
    };
    const createPoolStub = sinon.stub(mysql, 'createPool').returns(poolStub);
    const conn = new Conn();
    await conn.setConnection();
    await conn.executeQuery();
    sinon.assert.calledOnce(createPoolStub);
    sinon.assert.calledOnce(poolStub.getConnection);
    sinon.assert.calledWithExactly(poolStub.query, 'select 1 + 1 as solution');
    sinon.assert.calledOnce(poolStub.release);
  });
});

unit test result with coverage report:

  64112250
    ✓ should test conn.executeQuery


  1 passing (24ms)

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |   81.82 |      100 |   66.67 |      90 |                   
 Conn.js  |   81.82 |      100 |   66.67 |      90 | 19                
----------|---------|----------|---------|---------|-------------------

Upvotes: 2

Related Questions