Hacker News new | ask | show | jobs
by sambalbadjak 1919 days ago
I'd add to that, that test should be readable. personally I prefer to use: GIVEN, WHEN, THEN as comments in the tests. Also; it's ok not to be DRY while writing tests.
3 comments

> it's ok not to be DRY

Depending on context and implementation details, I'd say DRYing tests can be anywhere from indispensable to toxic.

I'm fine with creating libraries of shared functionality that tests can use, especially when it helps readability. If you've got several tests with the same precondition, having them all call a function named "givenTheUserHasLoggedIn()" in order to do the setup is a nice readability win. And, since it's a function call, it's not too difficult to pick apart if a test's preconditions diverge from the others' at a later date.

What I absolutely cannot stand is using inheritance to make tests DRY. If you've got an inheritance hierarchy for handling test setup, the cost of implementing a change to the test setup requirements is O(N) where N is the hierarchy depth, with constant factors on the order of, "Welp, there goes my afternoon."

I've gotten lured into the inheritance stuff and it's super nice at the very, very beginning and becomes a nightmare to maintain. Obviously a horrible tradeoff for software.

I've found that having a class/function as a parameter and explicitly listing the classes/functions that get tested is a small step back and way easier to maintain and read. It sets off some DRY alarms, cause usually that whole list is just "subclasses of X". And it seems like burden to update. "So if I make a new subclass, I have to add it everywhere?". Yes. Yes you do. Familiarity with the test suite is table stakes for development. You'll need to add your class name to like ten lists, and get 90% coverage for your work, then write a few tests about what's special about your class. When something breaks, you'll know exactly what's being tested. And you'll be able to opt out a class from that test with one keystroke.

That being said… I still have a dream of writing a library for generating tests for things that inherit from collections.abc. Something like “oh, you made a MutableSequence? let’s test it works like a list except where you opt-out.”

I'm an "it depends" fan myself.

It does annoy the many programmers who want clear and absolute rules for everything.

Then again they are always annoyed, living in a world where so many things "depend".

The given, when, then breakdown is interesting, though I've never seen language test utilities actually enforce that structure. Maybe an interesting potential experiment (regardless of language) ?

I feel like your last point is especially important. Sooooo many times have I seen over-abstracted unit tests that are unreadable and are impossible to reason about, because somebody decided that they needed to be concise (which they don't).

I'd much rather tests be excessively verbose and obvious/straightforward than over abstracted. It also avoids gigantic test helper functions that have a million flags depending on small variations in desired test behaviour...

As always, there are tradeoffs.

Personally, I work with some incredibly (100+line) long "unit" tests and they are a nightmare to work with.

Especially when the logic is repeated across multiple tests, and it's incorrect (or needs to be changed).

I really, really like shorter tests with longer names, but I'd imagine there are definitely pathologies at either end.

Are you reading my mind? I even blogged about it :) https://stribny.name/blog/2018/11/writing-test-cases-with-gi...