DEV Community


Discussion on: Unit testing is simple

lennartb profile image

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!

rubberduck profile image
Christopher McClellan

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.

scalawilliam profile image
William Narmontas Author • Edited

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".