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?
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
----------|---------|----------|---------|---------|-------------------