We did so by writing high level tests that were checking special patterns (gliders …). That was a nightmare ! It felt like trying to reverse engineer the rules of the game from real use cases. It did not bring us anywhere. -- Philippe Bourgau
I don't have this problem when I work top down.
The reason that I don't have this problem is that the "rules of the game" are sitting right there in the requirements, so I don't have to reverse engineer them from a corpus of examples.
What I do have to do is show the work. That happens during the refactoring phase, where I explicitly demonstrate how we arrive at the answer from the parameters of the question.
For a problem like the glider, the design might evolve along these lines: why is this cell alive? Because its live-neighbor-count in the previous generation was three. Where did that three come from? Well, it's a sum, we count 1 for each neighbor that is alive, and zero for each that is dead, for each of the eight neighbors. Where do the neighbors come from? We identify them by making eight separate calculations of using the coordinates of the target cell. And so on.
Sometimes, I imagine this as adding a comment to the hard coded answer, explaining why that answer is correct, and then introducing the same calculation in the code so that the comment is no longer necessary.
Paraphrasing Ward Cunningham, our goal is to produce code aligned with what we understand to be the proper way to think about the problem. Because we understand the rules of the game, we can align to them during the refactor phase without waiting for more examples to test.
Top down doesn't mean that you must jump to lion taming in one go. Top down refactorings tend to run deep, so it often makes sense to start with a examples that are narrow. It's not unreasonable to prefer more tests of lighter weight to a single "and the kitchen sink too" example.