|
Mocks, stubs, shims, etc. are usually just hiding the fact that the code to be tested is terrible, even in OOP languages. Furthermore side effects have nothing to do with testing one's code. Why? Because you have to test your own logic, not I/O or something else. I/O is already tested by someone else. So you actually don't care where the data comes from - the filesystem or a hardcoded string - you care if the output is correct after the respective transformations are applied to the input. And when you think about it testing shouldn't be that needed at all. In the OOP world, where state and identity are helplessly tied together and we are not working with values, but with references to values, tests might be a necessary evil. In the land of Functional however writing tests shouldn't be needed, at least in theory. Why? Because if you write small composable functions you should be able to test them right in the REPL. Corner cases? You have to think about them right from the start. TDD forces you to do so - then why shouldn't you when you have the immense power of a REPL? Once a function is ready you are not supposed to change it much. If you do you should change the inner workings and not the input/output. If you need to change the i/o most probably you need a different function. But what is more important is that if you needed to change the i/o and had tests for this function you would actually need to change the tests as well, which is more work (double? triple?) and no added value. |
This presupposes that you will always come up with an adequate design, and that you won't have to refactor this library of functions. For large enough systems, this is almost never the case. For sizeable systems in production, you will always come up against things you haven't thought of before.
Granted, proper factoring of your functions in the first place is going to help a lot. (Small composable functions.) However, if you claim that you can code such that you never ever have to change your mind about function signatures, never have to propagate changes across the system, even in large production systems, then you're either not seeing something, or you have some technique which you should be selling or basing a consulting practice around. (And/or, maybe I have something new to learn.)
EDIT: I have written projects in Clojure, including a multiplayer game server. This is the experience I'm basing this comment on.