단위 테스트 중에 만 사용되는 방법을 도입해도 괜찮습니까?


12

최근에 나는 공장 방법을 TDDing했다. 이 방법은 일반 객체 또는 데코레이터로 싸인 객체를 만드는 것이 었습니다. 데코 레이팅 된 오브젝트는 모두 StrategyClass를 확장하는 여러 유형 중 하나 일 수 있습니다.

내 테스트에서 반환 된 객체의 클래스가 예상대로인지 확인하고 싶었습니다. 일반 객체 OS가 반환되면 쉽지만 데코레이터 안에 싸서 할 때 어떻게해야합니까?

나는 PHP로 코딩하여 ext/Reflection랩핑 된 객체의 클래스를 찾는 데 사용할 수 있었지만 너무 복잡하고 TDD의 규칙을 다시 복잡하게하는 것처럼 보였습니다.

대신 getClassName()StrategyClass에서 호출 할 때 객체의 클래스 이름을 반환 한다고 소개하기로 결정했습니다 . 그러나 데코레이터에서 호출되면 데코 레이팅 된 객체에서 동일한 메서드로 반환 된 값을 반환합니다.

좀 더 명확하게하는 코드 :

interface StrategyInterface {
  public function getClassName();
}

abstract class StrategyClass implements StrategyInterface {
  public function getClassName() {
    return \get_class($this);
  }
}

abstract class StrategyDecorator implements StrategyInterface {

  private $decorated;

  public function __construct(StrategyClass $decorated) {
    $this->decorated = $decorated;
  }

  public function getClassName() {
    return $this->decorated->getClassName();
  }

}

그리고 PHPUnit 테스트

 /**
   * @dataProvider providerForTestGetStrategy
   * @param array $arguments
   * @param string $expected
   */
  public function testGetStrategy($arguments, $expected) {

    $this->assertEquals(
      __NAMESPACE__.'\\'.$expected,  
      $this->object->getStrategy($arguments)->getClassName()
    )
  }

//below there's another test to check if proper decorator is being used

내 요점은 다음과 같습니다. 단위 테스트를 쉽게하기 위해 다른 방법을 사용하지 않는 그러한 방법을 도입해도됩니까? 어쨌든 그것은 나에게 옳지 않은 느낌입니다.


이 질문은 아마도 programmers.stackexchange.com/questions/231237 / ... 질문에 대한 더 많은 통찰력을 줄 것입니다 . 나는 사용법과 메소드가 개발중인 응용 프로그램의 단위 테스트 및 디버깅에 크게 도움이 될지 여부에 달려 있다고 생각합니다. .
클레멘트 마크 AABA

답변:


13

내 생각은 당신은 아무것도하지 말아야, '아니요 오직 이 테스트 용이성을 위해 필요하기 때문입니다. 사람들이 내리는 많은 결정은 테스트 가능성과 테스트 가능성에 도움이되지만 주요 이점 일 수도 있지만 다른 장점에 대해서는 좋은 디자인 결정이되어야합니다. 이는 일부 원하는 속성을 테스트 할 수 없음을 의미합니다. 또 다른 예는 일부 루틴이 얼마나 효율적인지 알아야하는 경우입니다. 예를 들어 Hashmap은 균등하게 분산 된 해시 값 범위를 사용합니다. 외부 인터페이스에서는이를 알 수 없습니다.

"정확한 전략 수업을 받고 있습니까?" 라고 생각하는 대신 " 이 사양 이 테스트하려고 하는 것을 수행하는 수업 있습니까?" 내부 배관을 테스트 할 수 있으면 좋지만, 노브를 돌리고 뜨거운 물이나 찬 물이 나오는지 확인하면됩니다.


+1 OP는 TDD 기능 테스트가 아닌 '클리어 박스'단위 테스트를 설명합니다
Steven A. Lowe

1
팩토리 메소드가 제대로 작동하는지 테스트하고 싶을 때 StrategyClass 알고리즘 테스트를 추가하는 것을 꺼려하지만, 포인트가 있다고 생각합니다. 이런 종류의 분리 IMHO. 내가 피하고 싶은 또 다른 이유는 이러한 특정 클래스가 데이터베이스에서 작동하기 때문에 테스트하려면 추가 조롱 / 스터 빙이 필요하기 때문입니다.
Mchl

다른 한편으로이 질문에 비추어 볼 때 programmers.stackexchange.com/questions/86656/… "TDD 테스트"와 "단위 테스트"를 구별 할 때 이것은 완벽하게 괜찮습니다 (여전히 데이터베이스 배관은 : P)
Mchl

메소드를 추가하면 사용자와의 계약의 일부가됩니다. 테스트 전용 함수를 호출하고 결과에 따라 분기하는 코더가 생깁니다. 일반적으로 가능한 적은 수업을 공개하는 것을 선호합니다.
BillThor

5

이 점에 대한 나의 견해는-소스 코드를 약간 재 작업하여 테스트하기 쉽도록하는 경우가있다. 테스트 용으로 만 사용되는 함수로 인터페이스를 복잡하게 만드는 것은 이상적이지 않으며 변명해서는 안되므로 일반적으로 검토가 핵심입니다. 또한 코드 사용자가 객체와의 정상적인 상호 작용을 위해 테스트 인터페이스 기능을 갑자기 사용하는 상황에 처하기를 원하지 않습니다.

이것을 처리하는 내가 선호하는 방법 (그리고 주로 C 스타일 언어로 코딩 할 때 PHP 에서이 작업을 수행하는 방법을 보여줄 수 없다는 것을 사과해야합니다)은 '테스트'기능을 제공하지 않는 방식으로 제공하는 것입니다 객체 자체에 의해 외부 세계에 노출되지만 파생 된 객체에 의해 액세스 될 수 있습니다. 테스트 목적으로 실제로 테스트하려는 객체와의 상호 작용을 처리하고 단위 테스트에서 해당 특정 객체를 사용하도록하는 클래스를 파생시킵니다. C ++ 예제는 다음과 같습니다.

생산 유형 클래스 :

class ProdObj
{
  ...
  protected:
     virtual bool checkCertainState();
};

도우미 클래스 테스트 :

class TestHelperProdObj : public ProdObj
{
  ...
  public:
     virtual bool checkCertainState() { return ProdObj::checkCertainState(); }
};

그렇게하면 최소한 주 객체에서 '테스트'유형 기능을 노출 할 필요가없는 위치에 있습니다.


흥미로운 접근법. 어떻게 적응할 수 있는지 알아야합니다
Mchl

3

몇 달 전에 새로 구입 한 식기 세척기를 호스에서 많은 양의 물이 나왔을 때, 이것이 아마도 그것이 공장에서 제대로 테스트 되었기 때문일 것임을 깨달았습니다. 조립 라인에서 테스트 할 목적으로 만 기계에 장착 구멍과 물건을 보는 것은 드문 일이 아닙니다.

필요한 경우 테스트가 중요합니다.

그러나 몇 가지 대안을 시도하십시오. 리플렉션 기반 옵션이 그렇게 나쁘지는 않습니다. 필요한 것에 대한 보호 된 가상 접근자를 보유하고 테스트하고 주장 할 파생 클래스를 만들 수 있습니다. 아마도 클래스를 분할하고 결과 리프 클래스를 직접 테스트 할 수 있습니다. 소스 코드에 컴파일러 변수를 사용하여 테스트 방법을 숨기는 것도 옵션입니다 (PHP에서는 가능한지 확실하지 않습니다).

상황에 따라 데코레이터 내에서 적절한 컴포지션을 테스트하지 않고 장식에 예상되는 동작을 테스트 할 수 있습니다. 이것은 아마도 예상되는 시스템 행동에 초점을 맞추고 기술 사양에는 그다지 집중하지 않을 것입니다 (데코레이터 패턴은 기능적 관점에서 무엇을 구입합니까?).


1

나는 절대적인 TDD 초보자이지만 추가되는 방법에 달려있는 것 같습니다. 내가 TDD에 대해 이해 한 바에 따르면, 테스트는 API 생성을 어느 정도 "구동"해야합니다.

괜찮을 때 :

  • 메소드가 캡슐화를 중단하지 않고 오브젝트의 책임과 일치하는 목적을 제공하는 한.

괜찮지 않은 경우 :

  • 이 메소드가 결코 유용하지 않거나 다른 인터페이스 메소드와 관련하여 의미가없는 것처럼 보이면, 응집력이 있거나 혼동 될 수 있습니다. 그 시점에서, 나는 그 대상에 대한 나의 이해를 어지럽 힐 것이다.
  • Jeremy의 예는 "... 일부 루틴이 얼마나 효율적인지 알아야 할 때, 예를 들어 Hashmap은 고르게 분산 된 범위의 해시 값을 사용합니다. 외부 인터페이스에서는이를 알려주지 않습니다."
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.