For my money, this is the key point that people miss.
A test I like to use for whether two things are actually or just incidentally related is to think about “if I repeat this, and then change one but not the other, what breaks?”
Often the answer is that something will break. If I repeat how a compound id “<foo>-<bar>” is constructed when I insert the key and lookup, if I change the insert to “<foo>::<bar>” but not the lookup, then I’m not going to be able to find anything. If I have some complicated domain logic I duplicate, and fix a bug in one place but not the other, then I’ve still got a bug but now probably harder to track down. In these cases the duplication has introduced risk. And I need to weigh that risk against the cost of introducing an abstraction.
If I have a unit test `insert(id=1234); item = fetch(id=1234); assert item is not nil`, if I change one id but not the other, the test will fail.
But if I have two separate unit tests, and both happen to use the same id 1234, if I change one but not the other, absolutely nothing breaks. They aren’t actually related, they’re just incidentally the same.