0

I would like to unit test (mocha & chai) a pool connection (mysql) in my node.js app. I don't know if I'm using the tests in the correct way and, if so, why they are always qualified as "pending".

Giving the following code, how would I test it?

var pool = mysql.createPool({
    connectionLimit: 100,
    host: 'localhost',
    user: 'userName',
    password: 'userPass',
    database: 'userDatabase',
    debug: false
});

I have tried in many ways but it doesn't seem to work. Best I got was this:

describe("Database", function () {
    describe("Connection", function () {
        it("Should connect without an error", pool.getConnection(function (err, connection) {
            expect(err).to.be.null;
            })
        );
    })
});

Which would return, if credentials are correct:

Express server listening on port 8080
  Database
    Connection
      - Should connect without an error


  0 passing (15ms)
  1 pending

And return, if credentials are incorrect:

Express server listening on port 8080
  Database
    Connection
      - Should connect without an error
      1) Uncaught error outside test suite


  0 passing (23ms)
  1 pending
  1 failing

  1) Database Connection Uncaught error outside test suite:
     Uncaught AssertionError: expected [Error: ER_DBACCESS_DENIED_ERROR: Access denied for user 'userName'@'localhost' to database 'userDatabase'] to be null

Thank you in advance.

Faegy
  • 942
  • 1
  • 12
  • 29
  • Note that this is an integration test rather than a unit test. It tests that two systems work together rather than a single functional unit in *your* application is working well on its own. See http://stackoverflow.com/questions/1217736/how-to-write-unit-tests-for-database-calls for testing database calls. – Liam Gray Feb 24 '17 at 13:35

2 Answers2

3

What you pass to it in the 2nd argument must be a function. Right now you are doing:

it("Should connect without an error", pool.getConnection(...))

pool.getConnection takes a callback so in all likelihood, it returns undefined. So it looks like this to Mocha:

it("Should connect without an error", undefined)

And this is a pending test because having undefined for the callback is the way to tell Mocha the test is pending. You need to wrap your call to pool.getConnection in a function:

it("Should connect without an error", function (done) {
    pool.getConnection(function (err, connection) {
        if (err) {
            done(err); // Mocha will report the error passed here.
            return;
        }
        // Any possible tests on `connection` go here...

        done();
    });
});
Louis
  • 146,715
  • 28
  • 274
  • 320
  • If `expect(err).to.be.null` throws an exception, the `done()` will not be called, and hence the test won't resolve until it times out? – Liam Gray Feb 24 '17 at 13:51
  • That's true, but it is generally not an issue. 99.9999% of the time the test will pass and the timeout would not be hit. I've nonetheless edited my answer to show how it could be passed immediately. If the OP is not going to do any other tests in the callback then the OP could reduce it to what you have in your answer but if there is any testing on `connection` is going to be done, then `err` should be checked first. – Louis Feb 24 '17 at 13:58
  • And lets say I use `pool.getConnection()` in an object constructor and assign values from a query result to my object properties, would the `done()` call wait until my object is fully created when calling `var user = new User(1);` for example? – Faegy Feb 26 '17 at 10:22
  • Calling `done()` effectively marks your test as completed *as soon as the call happens*. You have to delay calling `done`. If you make your constructor work asynchronously the problem you run into is the same in testing **and** in production: testing needs to know when the constructor is done constructing the object, but production code also needs to know this. Otherwise, it will use the object too soon. Most "best practices" guide would tell you to make the constructor work synchronously and have any asynchronous operations be performed by methods called on the instance. – Louis Feb 27 '17 at 17:27
1

See testing asynchronous code in the mocha docs. Your it function should look similar to the below.

it('Should connect without an error', function (done) {
  pool.getConnection(done);
});

Or, if you want to add assertions inside your callback do the following:

it('Should connect without an error', function (done) {
  pool.getConnection((err, connection) => {
    try {
      expect(connection).to.not.be.null;
      expect(connection).to.have.property('foo');
      done();
    } catch (error) {
      done(error);
    }
  });
});

Note you should preferably test with promises because this allows you to run expect statements on the connection object without extra try/catch/done statements. For example, if pool.getConnection returns a promise, you can do:

it('Should connect without an error', function () {
  return pool.getConnection(connection => {
    expect(connection).to.have.property('foo');
    // more assertions on `connection`
  });
});

Also note that these are not "unit tests", but integration tests, as they are testing that two systems work together rather than just your application behaving as expected on its own.

Liam Gray
  • 1,089
  • 9
  • 16