People try out unit testing and give up because it’s hard.
There’s usually some code in the codebase that’s easy to test, and clearly valuable to have tests around. Stuff with few or no dependencies, with clear mappings of inputs to outputs. This stuff gets tested first and inspires few complaints.
But when we try to test the other stuff, it gets messy. The tests get long. They require a ton of setup. And when the code-under-test changes, we often find it difficult to update the tests. Sometimes a small change breaks a ton of tests. And so on.
Sometimes people run into this sort of thing and decide unit testing is hard or it’s not worthwhile or “it doesn’t work with the way I write code”.
Other times, people aren’t so hasty. They look at what’s causing a particular pain. They ask themselves, “Why is this hard?” and figure out how to change the way they designed that code so that pain goes away. The hard-to-test code starts to look more like the easy-to-test code.
That latter approach feels good, even just the first time. So they do it again. And again. It snowballs, and they get better at unit testing and better at design. (Because testability and good design are friends.)