Dans de nombreux cas, je pourrais avoir une classe existante avec un certain comportement:
class Lion
{
    public void Eat(Herbivore herbivore) { ... }
}
... et j'ai un test unitaire ...
[TestMethod]
public void Lion_can_eat_herbivore()
{
    var herbivore = buildHerbivoreForEating();
    var test = BuildLionForTest();
    test.Eat(herbivore);
    Assert.IsEaten(herbivore);
}
Maintenant, ce qui se passe, c'est que je dois créer une classe Tiger avec un comportement identique à celui du Lion:
class Tiger
{
    public void Eat(Herbivore herbivore) { ... }
}
... et comme je veux le même comportement, je dois faire le même test, je fais quelque chose comme ça:
interface IHerbivoreEater
{
    void Eat(Herbivore herbivore);
}
... et je refactorise mon test:
[TestMethod]
public void Lion_can_eat_herbivore()
{
    IHerbivoreEater_can_eat_herbivore(BuildLionForTest);
}
public void IHerbivoreEater_can_eat_herbivore(Func<IHerbivoreEater> builder)
{
    var herbivore = buildHerbivoreForEating();
    var test = builder();
    test.Eat(herbivore);
    Assert.IsEaten(herbivore);
}
... puis j'ajoute un autre test pour ma nouvelle Tigerclasse:
[TestMethod]
public void Tiger_can_eat_herbivore()
{
    IHerbivoreEater_can_eat_herbivore(BuildTigerForTest);
}
... puis je refactorise mes classes Lionet Tiger(généralement par héritage, mais parfois par composition):
class Lion : HerbivoreEater { }
class Tiger : HerbivoreEater { }
abstract class HerbivoreEater : IHerbivoreEater
{
    public void Eat(Herbivore herbivore) { ... }
}
... et tout va bien. Cependant, puisque la fonctionnalité est maintenant dans la HerbivoreEaterclasse, il semble maintenant qu'il y ait quelque chose de mal à avoir des tests pour chacun de ces comportements dans chaque sous-classe. Pourtant, ce sont les sous-classes qui sont réellement consommées, et ce n'est qu'un détail de mise en œuvre qui partage des comportements qui se chevauchent ( Lionset Tigerspeuvent avoir des utilisations finales totalement différentes, par exemple).
Il semble redondant de tester le même code plusieurs fois, mais il y a des cas où la sous-classe peut et remplace la fonctionnalité de la classe de base (oui, cela pourrait violer le LSP, mais avouons-le, IHerbivoreEatern'est qu'une interface de test pratique - elle peut ne pas avoir d'importance pour l'utilisateur final). Ces tests ont donc une certaine valeur, je pense.
Que font les autres dans cette situation? Déplacez-vous simplement votre test vers la classe de base ou testez-vous toutes les sous-classes pour le comportement attendu?
MODIFIER :
Sur la base de la réponse de @pdr, je pense que nous devrions considérer ceci: IHerbivoreEaterc'est juste un contrat de signature de méthode; il ne spécifie pas de comportement. Par exemple:
[TestMethod]
public void Tiger_eats_herbivore_haunches_first()
{
    IHerbivoreEater_eats_herbivore_haunches_first(BuildTigerForTest);
}
[TestMethod]
public void Cheetah_eats_herbivore_haunches_first()
{
    IHerbivoreEater_eats_herbivore_haunches_first(BuildCheetahForTest);
}
[TestMethod]
public void Lion_eats_herbivore_head_first()
{
    IHerbivoreEater_eats_herbivore_head_first(BuildLionForTest);
}
          Eatcomportement dans la classe de base, toutes les sous-classes doivent présenter le même Eatcomportement. Cependant, je parle de 2 classes relativement indépendantes qui partagent un comportement. Considérons, par exemple, le Flycomportement de Bricket Personqui, nous pouvons supposer, présentent un comportement de vol similaire, mais cela n'a pas nécessairement de sens de les faire dériver d'une classe de base commune.
                
Animalclasse qui contientEat? Tous les animaux mangent, et donc la classeTigeretLionpourrait hériter de l'animal.