I've recently opined, provocatively, that a test that never fails, adds no value.
At a more practical level I look to use the following practices.
- When writing code, start with a failing tests as recommended in TDD. Really do this on an ongoing basis.
- When hacking around in code, occasionally 'force' the test in question to fail using a known value or piece of logic that will do that. This is a key practice for me to make sure I have a good test. You'll get a sense after a while when a test is feeling 'suspiciously green'.
- Similar to the previous point, when working on a test and application code for a long period and you've finally finished it, force the test to fail one last time manually and then change it back to passing.
- Be aware and alert for both false negatives (test fails but should actually pass) and false positives (test passes but should fail)
- Be careful when using negative assertions to see that something 'does not' exist. Be sure it include a positive assertion about something else that should exist otherwise error pages such as 404's will still show the test as passing (incorrectly).
- Code Review of all code with review by at least two additional parties for each ticket. You mention issues that you stumble across. Maybe you can add more eyes on the code to try and find them more up-front.
- If there is an issue with intermittent failures, consider running the test thousands of times to examine stability.
Ideas such as 'delete tests that haven't failed in a year' are provocative and have some attraction but in practice I've never seen it and really can't imagine actually doing that. I have reviewed test suites and decided to remove tests due to duplication, slowness, fragility, not representing user functions, etc. but the mere fact they haven't failed in x period of time doesn't some like a criteria I'd be in favor of or able to convince my pair
Other ideas to address your specific points:
- Tests with missing assertions
You should be able to use your test framework to identify these. You may need to break out a tool like sed, awk or other search tools to help you.
- Tests that assert not what they supposed to assert
Make sure you have code review
- Logical errors resulting into assertions not being applied
Make sure tests fail first