The mocks.cr shard is really amazing! It’s one of the first things I looked for when I was researching testing with Crystal, and I can’t imagine working on a large test suite without a good mocking library.
I was able to fix all the specs and deprecation warnings and update it for Crystal 0.31.1.
However, I got stuck when I was trying to mock
File.read_lines, and I realized that this is because mocks.cr can’t mock a method when it has some default values for arguments.
crystal tool expand was super helpful to expand the mocking macros. However, these macros are pretty insane, so I’m not too sure how to spot the problem and find a fix. (Or maybe this is an issue with the Crystal language / compiler?)
I’m guessing this library isn’t used very much yet, since there isn’t a lot of activity in the GitHub issues. But should I be aware of any underlying reasons for the lack of popularity? Is it just because people don’t know about this library, or do people think it’s a bad practice to mock things like this?
I’ve worked with multiple large test suites and haven’t had a strong need for a generic mocking library. I considered it a few times, but always found better solutions.
When looking at the concepts employed by
mocks.cr (and any alternative implementation would certainly need to work similarly) there are a few issues that makes me try to avoid using it. The macros and runtime additions add a lot of complexity to the code and impact both compile and runtime performance. Especially in large test suites, this can add up, increasing time to test result.
Also, mock methods added by the library are global, adding additional overhead and friction for every single call to a method that is mocked somewhere in the test suite. In Crystal it’s not possible to limited a mock method to a single instance like in Ruby.
In general, I think it’s preferable to ensure your components are decoupled by design in order to allow testing them separately. This completely eliminates the need for a mocking tool.
I can see there might be cases where this is not possible or overly hard to do. But then I’d rather try to use a specialized mock for the specific case instead of a generic solution.That’s less hassle and more efficient.
The only mocking library I’ve used in Crystal is manastech/webmock.cr which is limited to http requests.
For other use cases I have similar thoughts to @straight-shoota.
Regarding the activity of waterlink/mocks.cr it’s been a while since I’ve see him around. If you feel more comfortable using mocks that changing the design maybe you will need to fork in order to move forward sooner. But give him some time before doing so
Regarding the limitation of named args with defaults it seems doable. I think the expansion of the
arg should end up using Arg#name when generating the calls in the mocked body.
Arg#name was not present when mock.cr was written.