Pruebe su código como alguien que lo usaría después de leer la documentación. No pruebe nada basándose en los conocimientos que tiene porque ha escrito o leído el código. Desea asegurarse de que su código se comporte como se espera.
En el mejor de los casos, debería poder usar sus pruebas como ejemplos, las pruebas de documentación en Python son un buen ejemplo de esto.
Si sigue estas pautas, cambiar la implementación no debería ser un problema.
También en mi experiencia es una buena práctica probar cada "capa" de su aplicación. Tendrás unidades atómicas, que en sí mismas no tienen dependencias y tendrás unidades que dependerán de otras unidades hasta que finalmente llegues a la aplicación que en sí misma es una unidad.
Debe probar cada capa, no confíe en el hecho de que al probar la unidad A, también prueba la unidad B de qué unidad A depende (la regla se aplica también a la herencia). Esto también debe tratarse como un detalle de implementación, incluso aunque puede sentir como si se estuviera repitiendo.
Tenga en cuenta que es poco probable que cambien las pruebas una vez escritas, mientras que el código que prueban cambiará casi definitivamente.
En la práctica, también existe el problema de IO y el mundo exterior, por lo que desea utilizar interfaces para poder crear simulaciones si es necesario.
En lenguajes más dinámicos, esto no es un gran problema, aquí puede usar la escritura pato, herencia múltiple y mixins para componer casos de prueba. Si empieza a no gustarle la herencia en general, probablemente lo esté haciendo bien.