Advantages: many APIs are stellar, way less runtime debugging (you actually get benefits from the unforgiving compiler), a sense of control, great performances
For APIs: Serde is an absolute banger.
Less clear: significant reliance on crates (third-party library). They're much easier to use than in Python (`cargo doc` in particular helps a lot as it provides a one-stop shop offline API documentation of all your dependencies as well as your own project) and there's more flexibility, but a 0-dep project is not going to be easy if that's your ideal. Then again if you're doing API stuff it probably is not as python's stdlib is quite crummy when it comes to web applications.
I love the docs in the Python ecosystem as a lot of them contain guides, examples on how to use the library is real world context. Rust library documentation often feels like if someone gave you a schema of all the components in your car, but not a driver's manual.
Rust's rules also make some of the complexities... not entirely necessary e.g. an object with a Drop can stand in for a setup/teardown quite nicely, thus standard packages like tempfile obviate the need for specific support.
However it's nowhere near the comfort of a pytest: while Rust doesn't have more overhead (a test function is just a function with a `#[test]` annotation)
- the missing scopes above "test" can be dear (especially because pseudo-globals like lazy_static and once_cell don't get dropped so there's no real teardown at the session level), though obviously some is understandable due to tests being multithreaded-by-default
- rust test-support-types are more verbose than fixtures
- the reporting is nowhere as precise as pytest's assertion rewriting
- the lack of parametric testing is annoying for reporting and addressing perspectives: "hand-rolled" table-based testing is OK, but the lack of subtests makes reporting less than ideal, and the inability to (re)run just one of the parametric tests can be frustrating
- it's missing a lot of the nice CLI options of pytest, especially about test-sets and run caches: marks, but also stepwise, exitfirst, last-failed, failed-first, new-first
The type system does compensate, to an extent, as it limits the test-space. Tremendously so if you purposefully encode your invariants in types.
A caveat here - doctests end up compiled into a separate binary for every test. I tried turning my unit tests into doctests, because they felt more natural there, but test iteration time went from 0.02 seconds to 14 seconds :(
Also there's a standard command for running tests in Rust but not Python.
Although I read there are crates to help with this, and it's indicative of bad programming styles...
In Rust that's not really an option because the types are so much stricter, and the loss of certainty on the other side makes things less convenient. Instead you'd use a tuple or throw a quick struct together (tuple or not). Defining structs is so habitual that it doesn't really feel unnatural or heavyweight.
It's like using dataclasses in Python, except the language also becomes helpful when you do that.