I've been writing test (in JavaScript) for the last two months. And, I have the habit of checking if module has some properties.
For example:
// test/foo.js
const Foo = require('../lib/foo');
const Expect = require('chai').expect;
describe('Foo API', () => {
it('should have #do and #dont properties', () => {
Expect(foo).to.have.property('do')
.and.to.be.a('function');
Expect(foo).to.have.property('dont')
.and.to.be.a('function');
});
});
});
And, I've been wondering if I am doing the right things. Just wanna know a few things:
Is this pattern "right"?
If its not "right"?
Does it even makes sense?
Don't test for types. Do test that specific property values conform to expected values.
So instead of "is foo a function", write a test that calls foo and expects a specific result.
If foo is not a function, you'll generate an error and the test will fail (which is good). If foo is a function, you'll have a proper test of that function's behavior.
There's a paradigm called duck typing that says (from Wikipedia):
In duck typing, a programmer is only concerned with ensuring that objects behave as demanded of them in a given context, rather than ensuring that they are of a specific class. For example, in a non-duck-typed language, one would create a function that requires that the object passed into it be of type Duck, or descended from type Duck, in order to ensure that that function can then use the object's walk and quack methods. In a duck-typed language, the function would take an object of any type and simply call its walk and quack methods, producing a run-time error if they are not defined. Instead of specifying types formally, duck typing practices rely on documentation, clear code, and testing to ensure correct use.
I would focus on the following part of above text:
In a duck-typed language, the function would take an object of any type and simply call its walk and quack methods, producing a run-time error if they are not defined
And...
[...] duck typing practices rely on documentation, clear code, and testing to ensure correct use.
That is, since JavaScript is a dynamically-typed language fits very well with duck typing.
In other words, you should avoid these tests. If a module has a missing property or it exists with an undesired type, you'll get a runtime error, which is enough to note that the caller doesn't fulfills the implicit contract to work fine with a given module.
The whole contract defined by the behavior of your code during run-time can be enforced by good documentation pages.
If you write a test it is because you want to be sure that further changes of the code will not change the behavior that you're testing.
So it is useful if your module expose those property as an interface and other code on your app or other apps depends on it.
But if the property, is just something "internals", I mean it is just dependent on the module implementation, than it is dangerous and a waste of time, as you should always be able to change implementation.
That's not true for interfaces.
On your tests, instead to test if a property is a function, you should test if the function do what should do when is called.
If there is a documentation that this function is an interface of the module.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With