많은 경우에 약간의 동작이있는 기존 클래스가있을 수 있습니다.
class Lion
{
public void Eat(Herbivore herbivore) { ... }
}
... 그리고 단위 테스트가 있습니다 ...
[TestMethod]
public void Lion_can_eat_herbivore()
{
var herbivore = buildHerbivoreForEating();
var test = BuildLionForTest();
test.Eat(herbivore);
Assert.IsEaten(herbivore);
}
이제는 라이온과 동일하게 행동하는 Tiger 클래스를 만들어야합니다.
class Tiger
{
public void Eat(Herbivore herbivore) { ... }
}
... 동일한 동작을 원하므로 동일한 테스트를 실행해야합니다.
interface IHerbivoreEater
{
void Eat(Herbivore herbivore);
}
... 그리고 테스트를 리팩터링합니다.
[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);
}
... 그리고 새로운 Tiger
수업에 대한 또 다른 시험을 추가합니다 .
[TestMethod]
public void Tiger_can_eat_herbivore()
{
IHerbivoreEater_can_eat_herbivore(BuildTigerForTest);
}
... 그리고 나는 내 클래스 Lion
와 Tiger
클래스를 리팩토링합니다 (일반적으로 상속, 때로는 구성).
class Lion : HerbivoreEater { }
class Tiger : HerbivoreEater { }
abstract class HerbivoreEater : IHerbivoreEater
{
public void Eat(Herbivore herbivore) { ... }
}
... 그리고 모든 것이 잘됩니다. 그러나 이제 기능이 HerbivoreEater
클래스에 있으므로 각 서브 클래스에서 이러한 각 동작에 대한 테스트를 수행하는 데 문제가있는 것 같습니다. 그러나 실제로 소비되고있는 서브 클래스를, 그리고 그들이 중복 행동을 공유하는 (일 만 구현 세부의 Lions
와 Tigers
예를 들어, 완전히 다른 최종 용도를 가질 수있다).
동일한 코드를 여러 번 테스트하는 것은 불필요한 것처럼 보이지만 하위 클래스가 기본 클래스의 기능을 재정의 할 수 있고 재정의하는 경우가 있습니다 (예, LSP를 위반할 수 있지만 직면 할 수 있음) IHerbivoreEater
는 편리한 테스트 인터페이스입니다. 최종 사용자에게는 중요하지 않을 수 있습니다). 따라서 이러한 테스트에는 가치가 있다고 생각합니다.
이 상황에서 다른 사람들은 무엇을합니까? 테스트를 기본 클래스로 옮기거나 예상되는 동작에 대해 모든 서브 클래스를 테스트합니까?
편집 :
@pdr의 답변을 바탕으로 우리는 이것을 고려해야한다고 생각합니다 IHerbivoreEater
. 동작을 지정하지 않습니다. 예를 들어 :
[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);
}
Eat
기본 클래스에 동작 을 넣으면 모든 하위 클래스가 동일한 Eat
동작을 나타냅니다 . 그러나 나는 행동을 공유하는 비교적 관련이없는 2 개의 수업에 대해 이야기하고 있습니다. 예를 들어, 고려 Fly
의 행동 Brick
과 Person
우리가 가정 할 수있는, 비슷한 비행 동작을 전시, 그러나 반드시 그들이 공통 기본 클래스에서 파생 가지고 이해가되지 않습니다.
Animal
가 포함 된 클래스 가 없어야합니다Eat
. 모든 동물은 먹고, 따라서Tiger
및Lion
클래스는 동물에서 상속 할 수있다.