Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I use tests for documentation. They seem like more work at the start, but they're more flexible. You can self-document things with tests that you cannot with just types.

For example, here are some tests from the lisp interpreter I've been working on: http://github.com/akkartik/wart/blob/8a8cf96816/030.test

You're right that tests aren't close to code. But that can be good or bad. Since it's not next to the code it can be more verbose and thorough without adding a constant reading burden. And when I wonder, "why is this line here?" I can comment it out and run the tests to find out.

I think of tests as records of the input space of my program. Most of the time we go to great lengths to make explicit what we do but not quite what aspects of its behavior we truly care about. Where are the dont-cares in this program? If I refactor it am I restricted to a bit-for-bit identical behavior? In practice that's impossible, and without tests we fudge random parts of the state space without rigorously knowing what is important and what isn't.



Static type systems don't excuse you from writing tests. But they do effectively write a whole class of tests for you, and run them much faster and give you more precise errors than manual testing ever will.

People complain about C++ compile times but I've heard of big Ruby projects with test suites that take 20+ hours to run.


> I've heard of big Ruby projects with test suites that take 20+ hours to run.

I'd assume those tests go well beyond type checking.


Sure but remember most static languages are 20+ times faster than Ruby so even with compile times you might still come out way ahead.


Ah, but a lot of bugfixes are developed by making small changes to understand better what is going on internally during the bug symptom, and there the compile time is more important than the compile/test time.


True, and languages that are slow to compile like C++ really suffer here. But Java and Go compile so quickly it's hardly an issue.


> You can self-document things with tests that you cannot with just types

Absolutely. But I would say that is a different debate. In my case, I don't want to specify the behavior, but only the form, which is the counterpart of a static type, but more flexible (e.g. {} is likened to any structure that behaves like a map - the class doesn't have to be exactly the same).

With my like-function, I don't have to spend too much time specifying what is expected, and I get a lot of bang for the buck.

I want to do just enough so the code stays comprehensible and thus manageable.

(fn parse-int [str] ...) needs no type or unit-test to be understood.

(fn parse-appointment [str] ...) is better understood when it has {:post [(like {:id (UUID.) :name "me" :date (java.util.Date .)} %)]}

And as soon as the function gets really smart, and it's smartness isn't revealed directly by the code, it would be time for either a good comment or a Unit Test (or make the code better so that it does, which is an often forgotten option).




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: