0

I am adding some config values before hapi server start. Application is works fine although in test I can not use config.get(). I can get around with proxyquire. So I was wondering

  • Is adding config file "dynamically" is bad design?
  • Is there a way I can use config.get() in such suitation?
  • Any alternative approach?

    //initialize.js
    
    const config = require('config');
    
    async function startServe() {
      const someConfigVal = await callAPIToGetSomeJSONObject();
      config.dynamicValue = someConfigVal;
      server.start(); 
    }
    
    //doSomething.js
    
    const config = require('config');
    
    function doesWork() {
      const valFromConfig = config.dynamicValue.X;
      // In test I can use proxiquire by creating config object
      ...
    }
    
    function doesNotWork() {
      const valFromConfig = config.get('dynamicValue.X'); 
      // Does not work with sinon mocking as this value does not exist in config when test run.
      // sinon.stub(config, 'get').withArgs('dynamicValue.X').returns(someVal);
      .....
    }
    
αƞjiβ
  • 3,056
  • 14
  • 58
  • 95

1 Answers1

0

Context: testing.

  • Is adding config file "dynamically" is bad design? => No. I have done it before. The test code changes configuration file: default.json in mid test to check whether function under test behaves as expected. I used several config utilities.
  • Is there a way I can use config.get() in such suitation? => Yes. For sinon usage, see the example below, which use mocha. You need to define the stub/mock before the function under test use it, and do not forget to restore the stub/mock. Also there is official documentation related to this: Altering configuration values for testing at runtime, but not using sinon.
const config = require('config');
const sinon = require('sinon');
const { expect } = require('chai');

// Example: simple function under test.
function other() {
  const valFromConfig = config.get('dynamicValue.X');
  return valFromConfig;
}

describe('Config', function () {
  it ('without stub or mock.', function () {
    // Config dynamicValue.X is not exist.
    // Expect to throw error.
    try {
      other();
      expect.fail('expect never get here');
    } catch (error) {
      expect(error.message).to.equal('Configuration property "dynamicValue.X" is not defined');
    }
  });

  it('get using stub.', function () {
    // Create stub.
    const stubConfigGet = sinon.stub(config, 'get');
    stubConfigGet.withArgs('dynamicValue.X').returns(false);
    // Call get.
    const test = other();
    // Validate te result.
    expect(test).to.equal(false);
    expect(stubConfigGet.calledOnce).to.equal(true);
    // Restore stub.
    stubConfigGet.restore();
  });

  it('get using mock.', function () {
    // Create mock.
    const mockConfig = sinon.mock(config);
    mockConfig.expects('get').once().withArgs('dynamicValue.X').returns(false);
    // Call get.
    const test = other();
    // Validate te result.
    expect(test).to.equal(false);
    // Restore mock.
    expect(mockConfig.verify()).to.equal(true);
  });
});

Hope this helps.

andreyunugro
  • 1,096
  • 5
  • 18