The best way I can express my question is with an example.
class foo{
constructor(size) {
this.bar = new Array(size);
}
baz(index) {
this.body[index] = true;
}
}
Ignoring the constructor, assume we're unit testing baz(). baz is logically expected to take an input index that's between 0 and bar.length - 1, but the following can also compile:
baz(['hey'])baz(5) // with an array size of 2baz(true)baz('0')
Now, I've been doing a lot of research on what we're actually testing with unit tests, and the best answer I can gather from what I read all around, is that, we're testing the function's behavior within the bounds of its logical contract with what/who's calling it. AKA, test implementation while implicitly assuming that it' called correctly.
I'm fully satisfied with this, but what I want to know is, where do we draw that line? None of the examples above will cause a typeerror, but I can disregard 1,3 and probably 4 if I'm to follow what I learned above.
But should I care about 2? Or do I also assume that the function's 'contract' will be upheld not only in terms of the inputs' implicit typing, but also their logical bounds.
Should I test and account for example 2 in my code?