3 ms·
The reason I use mocks is not primarily to avoid latency or setting things up, it's because it's the best way to test a permutation space in an isolated fashion
by kristiandupont 6y ago
The reason I use mocks is not primarily to avoid latency or setting things up, it's because it's the best way to test a permutation space in an isolated fashion.
Type systems are great and indeed many unit tests are a poor replacement for it, but for any moderately complex piece of logic, types can only make trivial guarantees.
Also, clever use of types might enforce something nicely, but they can still be really hard to work with. Error messages are often cryptic and don't describe anything semantic about the problem. A properly constructed unit test can easily tell you "You ended up returning a date that was set in the past compared to the expected outcome" which gives you much more information.
- hardwaresofton 6y ago> The reason I use mocks is not primarily to avoid latency or setting things up, it's because it's the best way to test a permutation space in an isolated fashion. So I think I've been talking past people on this point and not getting what people mean -- when I think of a "mock" I think of like a completely re-implemented piece of infrastructure. I am totally on board with the idea of mocking out individual methods and/or functions that indicate a certain point in the state permutation space. What I was trying to disagree with was the idea that people should be maintaining mocks/approximations of pieces of simple infrastructure (ex. Redis) they could just spin up. So in my opinion, never write an in-memory cache component (with redis operations like get/set/...) for a local integration test when you can just run redis. If you want to just test how some piece functions when Cache<Redis>.set(...) fails, then that totally makes sense to just mock out (as in make .set() throw/return an exception/error or whatever). > Type systems are great and indeed many unit tests are a poor replacement for it, but for any moderately complex piece of logic, types can only make trivial guarantees. > Also, clever use of types might enforce something nicely, but they can still be really hard to work with. Error messages are often cryptic and don't describe anything semantic about the problem. A properly constructed unit test can easily tell you "You ended up returning a date that was set in the past compared to the expected outcome" which gives you much more information. Can I introduce you to my friends Haskell and Rust? It really depends on the type system, but to be fair there's also quite a productivity trough early on working with these languages and trying to really take advantage of the expressiveness of their type systems. In the end you can't model out really complex logic -- but often you can definitely avoid writing the kind of things you would have checked for with units tests, and some integration tests at least. Agreed on the second point, but the languages mentioned above have made great strides in that respect, Rust was well known at the start for it's error message readability and Haskell is pretty decent at it, though the sticky situations you can get into in Haskell are an order of magnitude stickier. IMO that date question is a really good/easy problem for generated tests -- never producing a date that is in the past is a property that you're trying to maintain, and randomizing input is likely to be more effective in doing the fuzzing for the inputs. To be fair, that's more complexity than a simple unit test would add (especially in terms of simply preventing regression). >