Skip to content

Instantly share code, notes, and snippets.

@joecritch
Last active July 26, 2016 13:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save joecritch/7843fd5ad5bff8ef3a7f59623c578ce0 to your computer and use it in GitHub Desktop.
Save joecritch/7843fd5ad5bff8ef3a7f59623c578ce0 to your computer and use it in GitHub Desktop.
A request for a code review of how to go about unit testing dynamic-like config data

Mocking config data in tests

Structure

  • Each option has a set of values, which come from the app state
  • Options also each have a config, which are defined in configs.js (potentially a large list, with 'dynamic' data-like variations)

The tests

We're testing the summarise function. To isolate my tests, I've mocked the option configs. This means we don't have to couple the test to certain option configs, which allows an author to change the settings (e.g. option names) freely.

My tests work, but I feel it has a few issues:

  1. I can't directly spy on a config object, so I've exported a function getOptionConfig() which I can spy on. I feel like it would be cleaner to avoid an API; and just spy on the object if possible.
  2. I feel it'd be much cleaner to pass the _optionConfigs object to summarise() (to avoid mocks completely). However, this would only pass the same issue to any functions which call summarise().
  3. Because I'm forcing a return value in the spies, I'm not testing the parameter that I'm passing to getOptionConfig(). Is this bad?

Ideas?

I'm quite new to testing, so I'm potentially going about this incorrectly. Can anyone shed any light on how they'd tackle this global "static-yet-dynamic" config data in their tests?

const _optionConfigs = {
exampleOption: {
type: 'red',
},
exampleOption2: {
type: 'blue',
},
exampleOption3: {
type: 'red',
exclude: true,
},
exampleOption4: {
type: 'red',
},
// ... the list goes on...
};
export const getOptionConfig(id) {
return _optionConfigs[id];
}
import { getOptionConfig } from './config';
/**
* Summarise an option's values
* @param {string} optionName - an option name, used for referencing its config data
* @param {array} optionValues - application state. values of a particular option
* @returns {string} a summary of the option's values
*/
export const summarise(optionName, optionValues) {
const optionConfig = getOptionConfig(optionName);
if (optionConfig.exclude) {
return '';
}
if (optionConfig.type === 'red') {
return optionValues.map(value => value + ' with a dash of red').join(', ');
} else (optionConfig.type === 'blue') {
return optionValues.map(value => value + ' with a bit of blue').join(', ');
}
}
// ENV - jasmine
import * as configs from './configs';
describe('summarise', () => {
it('ignores when excluded', () => {
spyOn(configs, 'getOptionConfig').and.returnValue({
exclude: true,
type: 'blue',
});
const summary = summarise('testOption3');
expect(summary).toBe('');
});
it('summarises blue types', () => {
spyOn(configs, 'getOptionConfig').and.returnValue({
type: 'blue',
});
const summary = summarise('testOption2', [
'Value 1',
'Value 2',
]);
expect(summary).toBe('Value 1 with a bit of blue, Value 2 with a bit of blue');
});
it('summarises red types', () => {
spyOn(configs, 'getOptionConfig').and.returnValue({
type: 'red',
});
const summary = summarise('testOption', [
'Value 1',
'Value 2',
]);
expect(summary).toBe('Value 1 with a dash of red, Value 2 with a dash of red');
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment