Sadly, most posts/introductions about unit tests are usually way too simple with easy pure functions that just calculate some number. You don't have this kind of logic in real-world applications.
I have to deal with way more complicated scenarios daily involving object graphs that require initialization, external dependencies, drag and drop, framework objects that you can't mock and so on. I've yet to read a tutorial (or even book) that covers these cases.
How do I deal with legacy code that is not necessarily bad, but doesn't use DI and is not as easily testable as it ideally should be? How do I test public methods that don't return a value, but change something deeper down the call stack (internally)? I'd really like to read an article about how to tackle these problems!
Pick up a copy of Working Effectively with Legacy Code by Michael Feathers. It's an entire book about getting code that doesn't have tests into a harness. Essentially, how to deal with what you're talking about. It's worth every penny.
Great questions! I actually have a whole lot to say on this but that'd have to be a whole new article.
For greenfield, functional programming is the answer. You don't need to test "changes deeper down the call stack" because there's no such thing as a change. Pass a value, get a value back.
We've written large complex applications with two flavours of code:
unit-tested functional code.
functional/acceptance-tested mutable/side-effecting code, which wires up the functional code.
Both flavours test-driven, not test-after.
You say that this legacy code is not necessarily bad but missing testability. Assuming this, I say the following:
Approach it by repeatedly extracting as much purity from mutable parts as you can. You'll find there's a lot of code that does not actually need to be mutable.
Turn the left-over mutable parts into immutable parts.
Only do this incrementally and not in a single step. Small commits, small pull requests.
The cost of fixing is still less than rewriting from scratch. See Joel Spolsky's article about "Things you should never do".
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
Sadly, most posts/introductions about unit tests are usually way too simple with easy pure functions that just calculate some number. You don't have this kind of logic in real-world applications.
I have to deal with way more complicated scenarios daily involving object graphs that require initialization, external dependencies, drag and drop, framework objects that you can't mock and so on. I've yet to read a tutorial (or even book) that covers these cases.
How do I deal with legacy code that is not necessarily bad, but doesn't use DI and is not as easily testable as it ideally should be? How do I test public methods that don't return a value, but change something deeper down the call stack (internally)? I'd really like to read an article about how to tackle these problems!
Pick up a copy of Working Effectively with Legacy Code by Michael Feathers. It's an entire book about getting code that doesn't have tests into a harness. Essentially, how to deal with what you're talking about. It's worth every penny.
Great questions! I actually have a whole lot to say on this but that'd have to be a whole new article.
For greenfield, functional programming is the answer. You don't need to test "changes deeper down the call stack" because there's no such thing as a change. Pass a value, get a value back.
We've written large complex applications with two flavours of code:
Both flavours test-driven, not test-after.
You say that this legacy code is not necessarily bad but missing testability. Assuming this, I say the following:
The cost of fixing is still less than rewriting from scratch. See Joel Spolsky's article about "Things you should never do".