I have the following simple implementation: var VALIDATION_TYPES = { ERROR: 1, W
ID: 648232 • Letter: I
Question
I have the following simple implementation:
var VALIDATION_TYPES = {
ERROR: 1,
WARNING: 2
};
var validationRules = {};
this.addErrorRule = function (event, rule) {
addValidationRule(event, VALIDATION_TYPES.ERROR, rule);
};
var addValidationRule = function (event, type, rule) {
if (!validationRules[event]) {
validationRules[event] = {};
validationRules[event][VALIDATION_TYPES.ERROR] = [];
validationRules[event][VALIDATION_TYPES.WARNING] = [];
}
validationRules[event][type].push(rule);
};
I'm wondering whether addErrorRule should be unit-tested and if so how? Should I expose validationRules object to unit-tests?
EDIT:
I could modify my addValidationRule to return the number of rules added and check for that number in my test:
var addValidationRule = function (event, type, rule) {
var countAddedRules = 0;
if (!validationRules[event]) {
validationRules[event] = {};
validationRules[event][VALIDATION_TYPES.ERROR] = [];
validationRules[event][VALIDATION_TYPES.WARNING] = [];
}
var originalCount = validationRules[event][type].length;
validationRules[event][type].push(rule);
countAddedRules = originalAddedRulesCount - validationRules[event][type].length;
return countAddedRules;
};
Explanation / Answer
I think that both of the testing method proposed so far are bad.
omouse suggest exposing validationRules an internal implementation detail. In doing so, he is suggesting that you test the implementation when you should be testing the interface. See this blog for discussion.
The op then proposed returning the number of added rules. But as far as I can tell it will always return 1. Even if the method did return varying values, you'd only be testing the values it returned, not the actual functionality you are interested in.
So how do you test this method? Firstly, don't think of it in terms of how to test that method. Instead, think about what behavior you want to test. Don't think about the internal state, or how it does it. Think about how the method will be used in the rest of your program.
Presumably, you want to be able to do something like this:
validator.addErrorRule('foobar', function(payload) {
if (payload.cost > 50) {
return "No. Price Too High";
}
});
validation_results = validator.validate(payload)
All we need in order to turn that into a test is to say:
assert.deepEqual(validation_results, [
{validator: 'foobar', error: 'No. Price Too High'}
])
This actually tests the functionality we care about and avoids introducing implementation details.
Many coders have gotten the idea that they need to test each method independently. That's why people think they need to test addErrorRule separately from validate. Don't fall into this trap. Methods within the same object are usually tightly interconnected and attempting to test them independently is a fool's errand. Furthermore, you miss out on testing the interaction between the methods which is usually the entire point of the functionality you wanted.