Software Testing

I subscribe to the mantra: write tests, not too many, mostly integration tests.

Tests #1 benefit are giving you a measure of certainty that the program has not regressed as you make changes. In a sense, the behavior you test for has been "bolted down".

I don't write tests early on. When the specification and design are still in flux I specifically do not want to spend time writing tests I will only break later. The principle of "gradual stiffening" is relevant here.

Unit tests are useful mainly for small (usually pure) functions where the spec is well defined. Especially if the algorithm is complex. These provide assurance that the implementation is correct. Especially around edge cases.

Beyond that, I tend to write regression tests that spot check behavior of as large a chunk of the program as I can easily test. Again, the point is to give some confidence, once a change is made, that nothing else broke.

When writing in a highly dynamic lanugage (ie python) code coverage is very valuable, since a lot of errors can only be caught at run-time. Compare with say, rust, where you can lean more on the compiler.

A particularly difficult thing to test for me has been UI programs. There are sometimes plug ins and frameworks to test GUIs, but they can be a lot of work to setup and maintain. I'm generally going to look for ways to segment my user interaction tests from functional tests.

This leads to architectural decisions that separate logic from presentation.

However I prefer to avoid mocks whenever possible and instead use real input data, a real DB, actual network connections, etc, etc.

Sometimes this means writing tests that are sort of "outside" the program environment. Maybe a script or even a VM that starts your client and server as separate processes and then verifies database contents after a series of operations for example.

This requires production thinking.

One highly realistic integration test in a production-like environment is worth far more to me than high coverage unit tests, because where stuff tends to fail is at the interfaces.

This is all highly dependent on the individual situation. Cost vs. benefit should be your guiding light. Ego-less engineering and out of the box thinking are incredibly valuable.

nt to add one more tricky application: multi-threaded applications. I've had pretty good success at segmenting the program so that I can test threads both individually and integrated. Integrated multithreaded tests can be incredibly brittle. But a testable architecture is going to result in a more robust production architecture.

What are your thoughts on testing? Do you practice TDD? Do you have an example of a tricky application to test or something worked well?