Reputation: 7480
I have two functions, foo
and bar
.
function foo() {
if (arguments.length !== 1) {
throw new TypeError('only one argument expected');
}
do work;
}
function bar() {
if (arguments.length !== 3) {
throw new TypeError('exactly three arguments expected');
}
do work;
}
These functions were created according to TDD — e.g. tests were written first, then functions were implemented to make tests pass. List of tests:
foo()
is definedfoo()
does its job rightfoo()
throws TypeError
when given wrong number of argumentsbar()
is definedbar()
does its job rightbar()
throws TypeError
when given wrong number of argumentsAs you see, these functions both have duplicating functionality — they are testing for correctness of arguments each on it's own. As this check is going to be very common among my functions, and may go more complex (check for argument count to be in some range, check argument types etc), I've decided to move it out into separate decorator function check
.
So I've written tests for check
and implemented check
itself.
Now refactoring step — I've took an advantage of check
, so functions now look as follows:
foo = check(1, function() {
do work;
});
bar = check(3, function() {
do work;
});
What should I do now to tests that check for foo()
and bar()
take correct number of arguments? Can I drop them?
When I implement function buzz()
, that makes use of check()
immediately (as it's now used as way to define functions), do I have to write test for it to take correct number of arguments? I'm hesitating, because this test will be always green, as all job is done within decorator, so is there any need for test?
Upvotes: 1
Views: 251
Reputation: 11723
If there is a separate statement, you need a test. So in your case, you need to keep the tests that require that both foo()
and bar()
use the check
function. These tests may be simpler than the original tests that you wrote: For example they may only check that an error is thrown, without looking into the error message.
Should the check function now be broken to for example do nothing, there would be multiple tests that detect this. That is not an issue because you would put the test for the check
function at the top, and so the first failure will directly point to the root cause.
Upvotes: 0
Reputation: 818
I think you are on the right path, TDD make more evident the code duplication (the checking parameters code its duplication that must be removed with or without TDD) and you listen to your test and separate the responsibility of checking, now you have two responsibilities:
At a unit testing level this is perfect i think, perhaps in other point you need some integration or systems test that checks that your composing correctly the functions with his checkers.
Upvotes: 1
Reputation: 3455
Classical TDD concepts needs some additional modifications to apply them to dynamic language like Javascript (due to lack of classes, specific use of closures ...) That's way we have such testing libraries like Jasminejs. I can't tell you explicitly what to do with your functions, but I know that everything needs not to be tested. Some things really are so obvious that they just need some way of sanity check. Rule of thumb is to test things that can break. For example validations, database access, user input...
Upvotes: 1
Reputation: 5614
I would avoid to keep multiple unit tests that check the same code, because in the future:
check
function in a way that break your tests, you'll have to change 2 tests instead of one.check
, you'll get two failures: one referring to foo
and one referring to bar
, and it could not be obvious that what is broken is the check
function.So, I would keep only one set of tests, explicitly named as tests for the check
function, and even better, don't use function of your program to test them (not foo
neither bar
in your example) but use a fake function used only for tests purposes.
In this way, you can in future alter foo
or bar
to use, e.g., a check2 function without break tests of check function
This is, according to me, the best theoretical approach to go, but be pragmatic: don't try to follow this way if you don't expect to use the check
function in a great portion of your code: your target has to have the main program running smoothly, not a beautiful set of tests...
Upvotes: 3