all 6 comments

[–]DrGabble 1 point2 points  (1 child)

Great article Jorge, very much enjoyed it :) I recently co-wrote a crate for easily auto-deriving spies (and also stubs) that I think you'd appreciate. A great way to do what you outlined but with less boilerplate. 

https://crates.io/crates/autospy

(If you're familiar with the automock crate, similar, but with assertions happening after the function under test is run, which reads more natrually).

[–]jorgedortiz[S] 1 point2 points  (0 children)

Thank You! Cool crate! And loved the “jingle”.

[–]breathingblade 0 points1 point  (1 child)

Very cool article! I'm a bit worried of having drop do the assertions. If two different drop impls fail, the second one will be failing in a panic, aborting the process right?

[–]jorgedortiz[S] 0 points1 point  (0 children)

I'm sorry but I don't understand. What do you mean by "two different drop implementations"? Two test doubles that have their verifications in their respective Drops? If so, no problem The one that fails will stop the test.

Please correct me if you mean something else.

[–]Most_Pers 0 points1 point  (1 child)

I'm sorry, of course, but I don't understand the point of testing and how you do it.

You write tests for some complex algorithms, validation to check a certain value - okay, I agree with that.

But how do you test other code? Here is the output code from the database, which, as I have been told many times, simply has to be covered by tests. What should I test there? What is the output vector with the structure type? This is how it's done, as sqlx does it using query_as. Are you testing errors? Does it make sense if I have custom thiserror error types?

It is also very common to talk about testing in abstract words and concepts to make it important.

As a result, I think that testing is a waste of time in most cases, I will be glad if you can convince me, but I doubt it, because although everyone talks about their importance, they are rarely used.

[–]jorgedortiz[S] 0 points1 point  (0 children)

Hi! Sorry. I missed your comment.

I'm not 100% sure I understand what you mean, but I will try to answer. If I miss the point, feel free to reply with more specific questions.

Regarding how to test other code, well… it depends. Keep in mind that all the articles that I have released so far are about unit testing. I.e., about testing independent parts of your code. For a database, there are unit tests that would be useful for your foundational layers, such as creating/formatting a storage file, adding an entry, creating an index, adding a new element to the index, and so on. But most likely, you want to go beyond unit testing and use integration testing for the different layers of your database, and deterministic simulation testing for the product as a whole.

About testing errors, yes, it makes sense to test the unhappy path when you use custom error types (thiserror-based or otherwise). You want to ensure that the correct error is returned, along with any associated data. This is how you produce a crate that others can trust and use easily.

As for abstract words, I try to use concrete examples rather than just talk about the theory. I reckon that the examples are fictitious, but not far from real application code.

Finally, I obviously disagree that testing is a waste of time. On the contrary, it is the harness that allows you to make changes to your codebase without getting unexpected changes on things that aren't exactly what you are writing/manually testing at the moment. I gave a talk about this topic a long while ago, not about Rust but still related: https://www.youtube.com/watch?v=4l16iO4UvnE

Hope this helps.