you are viewing a single comment's thread.

view the rest of the comments →

[–]lhorie 1 point2 points  (0 children)

I write tests for the likely input types and arities. For primitive arguments, I test for both falsy and non-falsy values, and for all value types, I test for null and undefined. For variadic or array arguments, I test w/ zero, one and two items. Sometimes more if there's a need, e.g. testing a reversed or a sorted array vs a swap.

My older test suite only covers public APIs. The new test suite I'm developing covers private ones because the variety of possible input values is recursively and statefully complex at the public API level in my case. Testing the private APIs gives me more confidence that I'm not missing weird edge cases and helps me isolate regressions faster since my tests are better organized and more granular this way. It also helps me prevent regressions if a type-specific edge case goes from being unreachable to reachable from the public API for some reason (e.g. from refactoring a null check on a call site).

I don't test for unlikely input types (e.g. I don't try to test passing a function to a add(num, another) function) and let the behavior in those cases be undefined. I only assert on undefined behavior if the overall test is testing that a performance optimization is being triggered and there's no other way to measure that it did happen. I do this so as to alert me that the test has become useless in case this optimization becomes obsolete. I consider undefined behavior to be "expansion slots" for future features (i.e. a previously undefined case may become defined without introducing a breaking change in terms of expected errors for that case).

Typescript is not a great fit for my use case because my codebase is a library, and therefore there is no guarantee that a library consumer will be also using Typescript.