loading...

Unit Tests and Snapshots are Fake News

thejohnstew profile image John Stewart ・1 min read

Alright, I've been told many times that I'm wrong on this but I can't help but feel the same way every time I write or update one of these things.

When writing a unit test I end up stubbing out an entirely fake environment for a given function to run in. This fake environment yields the results I expect every time because I mocked it to do so. So the test passes or fails as expected.

Same is true for snapshots. When I update a React component's render method. Of course, the snapshots will need to be updated. With this one I can at least see that maybe if I update something not clearly referenced in the render method that it might update a snapshot inadvertently.

To me though these "tests" seem fake and not a true measure of if an app is well tested.

Again, I know I'm wrong but I'd love to hear from others on this because I honestly just don't see the value of these things.

Discussion

markdown guide
 

Unit tests are great for library code, where each unit is designed to be easily used by the outside world. For actual application code I prefer to rely more on integration tests.

 

"When writing a unit test I end up stubbing out an entirely fake environment for a given function to run in. This fake environment yields the results I expect every time because I mocked it to do so. So the test passes or fails as expected."

If your unit tests always pass it either means that:
A. you are literally a perfect programmer. Your code works 💯% of the time. "bugs" are a strange foreign concept.
B. Your unit tests are not thorough enough. You are not testing enough edge cases.

Given that A. is impossible as you are a mere mortal1 it must be B.
Maybe you are a really good programmer, but even the greatest makes mistakes. Unit tests help catch those mistakes by double-checking that your assumptions are correct.

Bugs usually happen in rare edge cases. Take a bit of time to think of those edge cases. For example, what if a user has two last names? Three? What if you get a negative number? A float? What if the timezone is different? What if it's a leap year? There's all sorts of possibilities with some imagination. By testing those scenarios you will make CERTAIN that they pass and those tests will remain to validate those edge cases for future programmers in the same codebase.

Also note that running unit tests in CI and preventing PR merge until test pass will make sure that nobody ignores broken tests.


  1. If you're not a mortal I apologize. Please don't smite me. 🙏 

 

I like snapshot tests but they're only as good as the Dev updating them... They're too easy to ignore & update when they fail - like you say, it's easy to have the attitude of "oh yeah of course I need to update them" rather than carefully inspect that the change is what you expected. Same goes for when someone is code reviewing that change... They need monitored carefully and I'm not sure they generally are

 

I think that's it. I haven't been on a project where these were looked at that closely.

 

For React components you can try Cypress to get more "real" tests. You can use unit-tests for "utilities" functions. I don't like snapshot tests. Screenshot tests can be useful as well. I like to use type checker (for example, TypeScript and io-ts). I didn't try property-based testing for JS, but this can be a nice option.

 

Do you have an example of that kind of unit tests?