Hacker News new | past | comments | ask | show | jobs | submit login

Well, the way unit tests work in Rust is that you write a test module inside your module. So, in a case like I'm describing, the unit test is usually (always?) right under the private function in question.

So, technically, yes, that's "observable behavior" in the sense that a test will pass or fail. It's not really the same IMO as running e.g., jUnit, where all of your tests are in the same area away from the code they're testing.

The reason I say that is because if you refactor and change the function in question, the test for it is RIGHT next to it. It's just going to be part of the refactor. It's almost like saying that private methods shouldn't depend on each other because taking one away will break the other. I believe your IDE will even show you squiggles when your test gets messed up while you're editing.

Your suggestion to use an interface is exactly the kind of "test-induced design damage" that's referred to in the OP. Which is what made me think to leave my comment. If you have a one-off pure function that is not used anywhere but inside one module, why in the world would we want to create an interface, then make an impl, then inject that interface into our module? Rust code is also not as class-driven as some other languages, so often times a module is just a collection of free functions. You'd have to inject this interface into every function, when the thing is never going to be different.

> Maybe YANGI but the idea is that its a code smell that you can't easily test core functionality from the public API. Why is the API so subtle? Is this class doing too much, should you break it up? These are the questions I ask when a junior dev makes a method public just to test it.

I don't disagree with that. It very well could/should be considered a smell. But sometimes a piece of smelly code checks out. And, while it should be used sparingly, testing private functions can sometimes save us from making our "actual" code more complicated than it needs to be, just for the sake of testability. Sometimes we can get good testability without adding extra ceremony.

EDIT: Also, one of the things that I sometimes struggle with when writing tests is: which public function's tests are responsible for testing the private functionality?

In other words, let's say I have a private function that formats a date a specific way. Two public functions depend on that functionality, plus do other things.

How do I verify that my date formatter is correctly implemented? I can do the whole iterface+impl+injection dance so that I can test my formatter (which was supposed to just be private implementation detail, but is now public so I can test it), or I can add some asserts to my tests for one of the public functions that depends on it. But which one? Do I test it in both places? Do I pick a favorite? Do I leave a note in one test explaining why it seems more involved than the sister function?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: