4 ms·
Haskell lets us have generic "mocks", which is -way- better than any kind of expectation-based mock. (admittedly, the example in andy's blog post doesn't show t
by mralston 11y ago
Haskell lets us have generic "mocks", which is -way- better than any kind of expectation-based mock. (admittedly, the example in andy's blog post doesn't show the power of this technique very well)
But my experience with mocks is that expectation-based mocks are fragile and make it easy to write tests that pass but are fundamentally wrong; if you just say you expect XYZ to come out of the database, even if your code gets refactored to not insert XYZ into the database earlier, the test will pass despite the code being completely broken.
With the haskell World approach, you don't have that - the fake database is fake because it's in memory (and thus very fast and uses a blank state for each test), but it's actually implementing the same semantics as the real database.
Some of the other IO stuff we've encapsulated is just expectation-based mocks and as you said that's not new, but it's still clean and doesn't require any changes to the code under test to make it mockable, which we did when we used mocks in our PHP.
- simplify 11y agoHow do you verify that your mock behaves exactly as the real database? The type system certainly helps with function signatures, but what about behavior?
- chadaustin 11y agoAs with any fake implementation of a service, you definitely need coverage that verifies that the fake and real have the same behavior.
- pron 11y agoIn-memory implementations are very useful, especially for larger tests, but, again, I don't see anything in Haskell that makes it easier. For example, on the JVM tests often use Google's Jimfs[1] in-memory file system (the JVM has pluggable file systems implemented as Java interfaces), and for relational databases they use H2[2]. None of this requires any code changes, perhaps thanks to the JVM's extreme pluggability. The JVM uses SPIs for almost everything, from encryption to filesystems to sockets -- you can fake the entire OS (almost) in Java, and what you can't fake easily, you can still fake with an agent (unrelated, but starting in Java 9, even the JIT is pluggable, so you can control machine-code generation at any granularity you want). Just since my conversation here with chadaustin, I've written a small library that uses an agent to make the entire JVM use a virtual clock[3] -- again, with no code changes necessary in the tested code. [1]: https://github.com/google/jimfs https://github.com/google/jimfs [2]: http://www.h2database.com/html/main.html http://www.h2database.com/html/main.html [3]: https://github.com/puniverse/timewarp https://github.com/puniverse/timewarp