

Writing unit tests is reinventing functional programming (2009) - tosh
http://noss.github.io/2009/02/25/writing-unit-tests-is-reinventing-functional-programming-in-non-functional-languages.html

======
Ixiaus
No one is reinventing functional programming, as another commenter said,
_purity_ is just one aspect of functional programming and unit testing is used
heavily in functional programming projects. In languages like Haskell where
the type system can do most of the heavy lifting for you (ala QuickCheck -
Erlang has a version of it too if you use spec definitions piously) unit
testing is less repetitive and much easier to maintain.

What unit testing is in languages that don't have a stronger type system is
simply working around warts in language design. Just as ORM systems are a
"work around" for the warts in interfacing relational data with an object
model.

[EDIT] I didn't write out my thought well enough: unit testing in "other
languages" isn't necessarily working around the warts in language design but
working around the warts in programmer thinking and process. Strongly typed
languages don't solve those problems but they do improve the situation
dramatically with their type guarantees and advanced testing systems
(QuickCheck) therefore reducing the amount of cognitive overhead and code
maintenance involved in writing tests. With languages like Haskell you only
write Unit Tests for things that are difficult or complex to test using
QuickCheck.

------
vsbuffalo
Can functional programming languages guarantee software regression never
happens? No? Then I'd argue they still need unit testing.

Side-effects create additional problems, but functional programming doesn't
solve all problems inherent in programming.

------
ams6110
One point in support of this point of view is that with functional languages
such as erlang and haskell you can generate unit tests using something like
quickcheck.

<http://en.wikipedia.org/wiki/QuickCheck>

~~~
joesb
_Re-implementations of QuickCheck exist for C,[2] C++,[3] Chicken Scheme,[4]
Clojure,[5] Common Lisp,[6] D,[7] Erlang,[8][9] F#,[10] Factor,[11] Io,[12]
Java,[13][14][15] JavaScript,[16] Node.js,[17] Objective-C,[18] OCaml,[19]
Perl,[20] Python,[21] Ruby,[22] Scala,[23] Scheme,[24] Smalltalk[25] and
Standard ML.[26]_

~~~
tikhonj
The problem is that most of those implementations--even the OCaml one--are
much more awkward to use than the Haskell version. So people don't.

In Haskell, the type system--thanks to typeclasses--can figure out how to
generate random inputs automatically, just based on what type is expected.
Even if you have a custom type, it's incredibly easy to define how to generate
elements and then use it everywhere. Or you could easily randomly generate
values in an ad-hoc method wherever they're used.

This takes advantage of the fact that in Haskell, values can be polymorphic on
their _return_ types. As far as I know, this is a feature unique to
typeclasses--and very few languages aside from Haskell support those. (I only
know of one other: Rust.) This, combine with Haskell's usual popular
abstractions like Applicative Functors, makes writing QuickCheck-style
properties and new random generators much easier.

Of course, this particular reason has nothing to do with functional
programming and everything to do with Haskell's glorious type system. However,
functional programming _does_ play a role in QuickCheck's popularity as well.

Basically, QuickCheck-style tests are primarily useful for code that does not
have side effects. QuickCheck lets you check some invariant by evaluating the
same function hundreds or thousands of times with randomly generated input.
This style simply does not scale to non-trivial non-local state, much less
actual IO.

So even if your language had a usable QuickCheck library, it would only be
useful for the more functional parts of your code. As the article points out,
unit tests push you towards a functional style to some extent. QuickCheck does
this _far more_. And so most people writing rampantly imperative code in
wantonly imperative languages simply don't use QuickCheck. Even if some
intrepid soul _has_ ported it.

~~~
laureny
> In Haskell, the type system--thanks to typeclasses--can figure out how to
> generate random inputs automatically, just based on what type is expected.

No. The reason why the type system is able to generate these values is because
of algebraic data types, not type classes.

Type classes are completely unrelated to this problem.

~~~
tikhonj
What?

The way the Arbitrary class works is only possible thanks to typeclasses.
Without typeclasses, you would have to explicitly specify which generator to
use. Thanks to the typeclass system, Haskell can just infer this.

On the other hand, none of the Arbitrary machinery is particularly tied to
algebraic data types _per se_. It would work as well if you had OO style
constructors instead.

Just take a look at the OCaml version of QuickCheck to see what I mean. OCaml
obviously has algebraic data types, but it's still far more awkward to use
QuickCheck there.

------
mbrock
I wish!

Unit tests that verify the in-order invocation of several different void
methods have nothing to do with reinvention of purity.

I think a better argument would be: the best way to write testable units is to
write pure functions. This argument was made for example in Hughes's _Why
Functional Programming Matters_. But it's not really a question of OO vs FP.

There's a seemingly important pattern that I don't know if there's a common
name for. It's something like "Replace Side-Effect With Value." Or maybe
"Inversion of Side-Effecting." This is relevant even in Haskell. Either you
write your whole program as a big messy monad transformer stack with IO at the
top -- I don't know how to unit test that, much less prove anything -- or you
define the application logic as pure functions that give instructions to a
simple driving "side-effect interpreter."

XMonad, the Haskell window manager, is written in this latter way, with lots
of unit tests too. There's a cool video walkthrough of how the code works --
<http://www.youtube.com/watch?v=63MpfyZUcrU> \-- and a document called _Guided
tour of the xmonad source_ \--
[http://www.haskell.org/haskellwiki/Xmonad/Guided_tour_of_the...](http://www.haskell.org/haskellwiki/Xmonad/Guided_tour_of_the_xmonad_source).

------
adrianhoward
Meh. Among the other reasons for testing the author didn't touch on:

* It's not always about the tests. I TDD code (functional as well as OO - hell procedural come to that) as a _design_ tool - not a testing tool. I write acceptance tests as tools to help us understand when we reach "done" and as ways to track progress.

* It's about stopping regressions. Test suites get in the way of accidental behaviour changes.

* There a way to scale team communication of how the code should behave.

I love FP dearly, but if it replaced testing why do I see so much FP code with
test suites ;-)

------
millstone
What the author describes seems to be just modularity and encapsulation. The
properties most associated with FP, like first class functions, don't appear
to be related to unit tests.

------
joesb
There's nothing wrong with applying part of good practice from other
languages. Referential transparency is one property of FP, but FP does not
hold exclusive right to it. Quit trying to sound like smug.

~~~
nightski
I am not aware of any non-FP languages that track referential transparency in
the type system.

------
flyinglizard
This is simply 'good' programming.

------
MostAwesomeDude
As is becoming increasingly common, people are conflating "functional
programming" with "immutable data types" or "side-effect-free functions",
neither of which are core concepts common to all "functional programming
languages." It's getting quite tiresome.

------
hayksaakian
Can we add [2009] to the title?

~~~
MetaCosm
It has been very zombierific on HN the last few days.

