I have been leaning towards keeping my test hierarchy as flat as possible. I think tests should be easy to follow, and the added cognitive complexity of keeping an extra class hierarchy in mind while working through the actual problems that you are trying to solve is unnecessary. I'm not saying that it should be totally flat though, I do see the benefit of having shared setups, teardowns, and general utility methods/properties, with the ability to extend the functionality like in JP's Specification base class.
A developer on my team just checked in a few abstract base test fixtures, about 1 for every abstract base class. This totally flew in the face of my afore mentioned belief, but being the lazy programmer that I am I did like the ability to write tests once that would be run against all the classes that inherit the abstract base classes. But after getting into them a bit more I've noticed some hacks that were added in order to make them work; i.e. a latch to make sure that some Expect.Call(...)s weren't added for tests that were using the mocks differently, and having to explicitly call the setup method from certain tests. I also didn't like the fact that I couldn't easily run one of the tests in the abstract fixture because the object it was testing wouldn't be instantiated because that happened in the inheriting fixture's setup, so the test would fail with a NullReferenceException... which is what really turned me off to this approach.
Thinking about it last night, I came to the conclusion that the ends here do not necessarily justify the means. I mean, if I can write a fixture that tests the inherited functionality in one of the normal concrete implementations, shouldn't that be enough to prove that it will work in the rest? While any implementation that overrides that functionality should have it's own set of tests, which would have had to override the tests in the BaseFixture anyway.
How do you guys handle test hierarchy?