게터와 세터에 대해 단위 테스트를 작성해야합니까?


141

게터와 세터에 대한 테스트를 작성해야합니까, 아니면 과잉입니까?


나는 그렇게 생각하지 않습니다. getter / setter에 대한 테스트 케이스를 작성해서는 안됩니다.
Harry Joy

1
나는 당신이 자바를 의미한다고 생각합니까? 이것은 특히 현대적인 언어의 경우 Java에 대해서는 특히 심각한 질문입니다.
skaffman 2016 년

@skaffman 어떤 현대 언어에는 속성이 없습니까? 물론 Java와 같은 언어는 전체 메소드 본문이어야하지만 C #과 논리적으로 다르지 않습니다.
Claus Jørgensen 2016 년

2
@Claus : 그는 속성을 말하지 않았고 게터와 세터는 말했다. Java에서는 수동으로 작성하고 다른 언어에서는 더 나은 지원을받습니다.
skaffman 2016 년

2
왜 게터와 세터가 전혀 없는지 물을 수도 있습니다 .
Raedwald

답변:


180

나는 아니오라고 말할 것입니다.

@ 윌은 100 % 코드 범위를 목표로 삼아야한다고 말했지만 내 생각에는 위험한 혼란입니다. 적용 범위가 100 % 인 단위 테스트를 작성할 수 있지만 전혀 테스트 할 수는 없습니다.

단위 테스트는 표현적이고 의미있는 방식으로 코드의 동작을 테스트하기 위해 제공되며 게터 / 세터는 끝의 수단 일뿐입니다. 테스트에서 getter / setter를 사용하여 "실제"기능을 테스트한다는 목표를 달성하면 충분합니다.

반면에, getter와 setter가 단지 get and set 이상의 기능을 수행하는 경우 (즉, 적절하게 복잡한 방법) 테스트를 받아야합니다. 그러나 단위 테스트 케이스를 작성하지 않는 단지 시간 낭비 게터 또는 세터를 테스트합니다.


7
100 % 코드 범위를 목표로하는 것은 어리석은 일입니다. 결국 공개되지 않은 코드 및 / 또는 복잡하지 않은 코드를 다루게됩니다. 이러한 것들이 자동 생성에 가장 적합하지만 자동 생성 테스트조차도 무의미합니다. 통합 테스트와 같이 중요한 테스트로 초점을 이동하는 것이 좋습니다.
Claus Jørgensen 2012 년

7
@Claus : 통합 테스트에 중점을 두는 것을 제외하고는 동의합니다. 단위 테스트는 우수한 디자인에 중요하며 통합 테스트를 보완합니다.
skaffman

5
전체 테스트 스위트가 실행될 때 100 % 코드 범위가 좋은 목표라고 생각합니다. 속성 게터 설정 기 및 기타 코드는 더 큰 테스트의 일부로 실행됩니다. 마지막으로 다루어야 할 부분은 아마도 오류 처리 일 것입니다. 그리고 오류 처리가 단위 테스트에 포함되지 않으면 절대로 포함되지 않습니다. 한번도 실행 된 적이없는 코드가 포함 된 제품을 배송 하시겠습니까?
Anders Abel

나는이 조언에 동의하지 않는 경향이있다. 예, 게터와 세터는 간단하지만 놀랍게도 쉽게 망칠 수 있습니다. 몇 줄의 간단한 테스트를 통해 테스트 중이며 계속 작동하고 있음을 알고 있습니다.
Charles

'둥근'POJO를 갖기 위해 사용자 (또는 도구)가 작성한 불필요한 세터를 테스트하고있을 수 있습니다. 인스턴스 당 Gson.fromJson을 사용하여 POJOS를 "확장"할 수 있습니다 (세터 필요 없음). 이 경우 사용하지 않는 설정기를 삭제하는 것이 좋습니다.
Alberto Gaona

36

Roy Osherove는 그의 유명한 저서 'The Art Of Unit Testing'에서 다음과 같이 말합니다.

속성 (Java의 getter / setter)은 일반적으로 로직을 포함하지 않으며 테스트 할 필요가없는 코드의 좋은 예입니다. 그러나 조심하십시오 : 일단 속성 내부에 검사를 추가하면 논리가 테스트되고 있는지 확인해야합니다.


1
그것들을 테스트하는 데 걸리는 시간과 행동이 추가 될 가능성을 고려할 때 왜 그럴 수 없는지 모르겠습니다. 나는 그가 눌렀다면 "음, 왜 안 되겠나"라고 대답 할 것이라고 생각합니다.
Sled

1
중요한 초기 책에는 종종 나쁜 조언이 있습니다. 나는 사람들이 게터와 세터를 빨리 던지고 그들이 잘라서 붙여 넣거나 잊어 버렸기 때문에 실수를하는 많은 경우를 보았습니다. 또는이-> 또는 이와 유사한 것. 테스트하기 쉽고 반드시 테스트해야합니다.
Charles

35

TDD와 함께 울리는 YES


참고 :이 답변은 잠재적으로 나쁜 조언이기는하지만 계속 upvotes를 얻습니다. 이유를 이해하려면 아래의 여동생을 살펴보십시오 .


논란의 여지가 있지만, 나는이 질문에 '아니오'라고 대답하는 사람은 TDD의 기본 개념이 누락되었다고 주장합니다.

나를 위해, 대답은 울려 퍼지는이다 예는 는 TDD를 수행합니다. 그렇지 않다면 그럴듯한 대답은 없습니다.

TDD의 DDD

TDD는 종종 주요 이점이 있다고 인용됩니다.

  • 방어
    • 코드가 변경 될 수 있지만 동작 이 변경 되지 않도록 보장 .
    • 이것은 리팩토링의 매우 중요한 관행을 허용합니다 .
    • 이 TDD를 얻거나 얻지 못합니다.
  • 디자인
    • 당신은 지정 무엇인가, 어떻게의 동작을해야 무엇을해야 구현하기 전에 그것을.
    • 이것은 종종보다 현명한 구현 결정을 의미 합니다.
  • 선적 서류 비치
    • 테스트 스위트는 사양 으로 사용되어야합니다 (요구 사항) 문서 .
    • 그러한 목적으로 테스트를 사용한다는 것은 문서와 구현이 항상 일관된 상태임을 의미합니다. 하나를 변경하면 다른 것으로 변경됩니다. 별도의 워드 문서에서 요구 사항과 디자인을 유지하는 것과 비교하십시오.

구현과 별도의 책임

프로그래머로서, 속성을 중요성과 게터로 생각하고 일종의 오버 헤드로 세터를 생각하는 것은 대단히 유혹적입니다.

그러나 속성은 구현 세부 사항이며 세터와 게터는 실제로 프로그램을 작동시키는 계약 인터페이스입니다.

객체가 다음과 같이 철자를 작성하는 것이 훨씬 더 중요합니다.

클라이언트가 상태를 변경하도록 허용

클라이언트가 상태를 쿼리하도록 허용

그런 다음이 상태가 실제로 저장되는 방법 (속성이 가장 일반적이지만 유일한 방법은 아닙니다).

다음과 같은 테스트

(The Painter class) should store the provided colour

TDD 의 문서 부분에 중요합니다 .

테스트를 작성할 때 최종 구현이 사소한 (속성) 방어 이점 이 없다는 사실을 알 수 없습니다.

왕복 공학의 부족 ...

시스템 개발 세계의 주요 문제 중 하나는 왕복 공학 의 부족입니다. 1- 시스템의 개발 프로세스가 분리 된 하위 프로세스로 분할됩니다 (문서, 코드).

1 브로디, 마이클 L. "존 마일로 풀 로스 : 개념적인 모델링의 재봉 씨." 개념 모델링 : 기초 및 응용. Springer Berlin Heidelberg, 2009. 1-9.

... 그리고 TDD가이를 해결하는 방법

시스템 및 해당 코드의 스펙이 항상 일관되도록 TDD 의 문서 부분입니다.

먼저 디자인하고 나중에 구현

TDD 내에서 먼저 합격 합격 테스트를 작성한 다음 통과 할 수있는 코드 만 작성하십시오.

높은 수준의 BDD 내에서 먼저 시나리오를 작성한 다음 통과시킵니다.

왜 세터와 게터를 제외시켜야합니까?

이론적으로 TDD 내에서 한 사람이 테스트를 작성하고 다른 사람이 테스트를 통과시키는 코드를 구현할 수 있습니다.

그러므로 스스로에게 물어보십시오 :

클래스 테스트를 작성하는 사람이 getter 및 setter를 언급해야합니다.

getter와 setter는 클래스에 대한 공용 인터페이스이므로 대답은 명백히 yes 이거나 객체의 상태를 설정하거나 쿼리 할 방법이 없습니다. 그러나이 작업을 수행하는 방법이 각 방법을 개별적으로 테스트하는 것은 아닙니다 . 자세한 내용은 다른 답변 을 참조하십시오.

분명히 코드를 먼저 작성하면 답이 명확하지 않을 수 있습니다.


2
그것은 동전의 한 면일뿐입니다. 테스트를 위해 테스트 대신 수행 할 수있는 작업을 생각해보십시오. 켄트 벡 (Kent Beck)이 말했듯이 작업 테스트가 아닌 작업 코드에 대한 비용을 지불합니다.
Georgii Oleinikov

@GeorgiiOleinikov 아래에서 다른 답변을 읽어 보셨습니까? 그것은 당신의 견해와 거의 일치합니다.
Izhaki

21

TL; 박사 : 당신이 해야 하고, 함께 OpenPojo 사소한입니다.

  1. 게터와 세터에서 약간의 유효성 검사를 수행해야하므로 테스트해야합니다. 예를 들어, setMom(Person p)자신보다 어린 사람을 어머니로 설정해서는 안됩니다.

  2. 지금도 그 일을하고 있지 않더라도 미래에 일어날 확률은 회귀 분석에 도움이 될 것입니다. 당신이 어머니를 설정하게하려는 경우 null, 나중에 누군가가 그것을 바꿀 수 있는지 테스트해야합니다. 그러면 당신의 가정이 강화 될 것입니다.

  3. 일반적인 버그는 void setFoo( Object foo ){ foo = foo; }어디에 있어야 하는가void setFoo( Object foo ){ this.foo = foo; } . (첫 번째 경우 foo에 작성되는 것은 오브젝트 의 필드가 아닌 매개 변수입니다 ).foo

  4. 배열이나 컬렉션을 반환하는 경우 getter가 반환하기 전에 setter로 전달 된 데이터의 방어 복사본 을 수행 할 것인지 테스트해야합니다 .

  5. 그렇지 않으면 가장 기본적인 세터 / 게터가 있다면 단위 테스트를 수행하면 객체 당 최대 10 분 정도가 추가되므로 손실은 무엇입니까? 동작을 추가하면 이미 골격 테스트를 받았으며이 회귀 테스트를 무료로받을 수 있습니다. Java를 사용하는 경우 OpenPojo있으므로 변명의 여지가 없습니다 . 사용 가능한 기존 규칙 세트가 있고 전체 프로젝트를 스캔하여 규칙 내에서 일관되게 적용되도록 할 수 있습니다.

그들의 예에서 :

final PojoValidator pojoValidator = new PojoValidator();

//create rules
pojoValidator.addRule( new NoPublicFieldsRule  () );
pojoValidator.addRule( new NoPrimitivesRule    () );
pojoValidator.addRule( new GetterMustExistRule () );
pojoValidator.addRule( new SetterMustExistRule () );

//create testers
pojoValidator.addTester( new DefaultValuesNullTester () );
pojoValidator.addTester( new SetterTester            () );
pojoValidator.addTester( new GetterTester            () );

//test all the classes
for(  PojoClass  pojoClass :  PojoClassFactory.getPojoClasses( "net.initech.app", new FilterPackageInfo() )  )
    pojoValidator.runValidation( pojoClass );

11
나는 이것이 오래되었다는 것을 알고 있지만 : 게터와 세터에서 유효성을 검사해야합니까? 나는 setMom이 말하는 것을해야한다는 인상을 받았습니다. 유효성을 검사하는 경우 validateAndSetMom이 아니어야합니까? 또는 유효성 검사 코드가 단순한 객체보다 존재하지 않아야합니까? 내가 여기서 무엇을 놓치고 있습니까?
ndtreviv 2016 년

14
예, 항상 입력을 확인해야합니다. 그렇지 않다면 왜 공개 변수를 사용하지 않습니까? 같은 것이됩니다. setter와 변수를 사용하면 얻을 수있는 이점은 음수가되는 나이와 같이 개체가 유효하지 않은지 확인할 수 있다는 것입니다. 객체에서이 작업을 수행하지 않으면 "service" god object 와 같은 다른 곳에서 수행하게 되며, 그 시점에서 실제로 OOP가 아닙니다.
Sled

1
글쎄요, 아마도 이번 주 하이라이트 일 것입니다. 감사합니다.
Sled

19

예, 항상 고립 된 것은 아닙니다

정교하게 해주세요 :

단위 테스트 란 무엇입니까?

에서 레거시 코드를 효과적으로 작업을 1 :

단위 테스트라는 용어는 소프트웨어 개발에서 오랜 역사를 가지고 있습니다. 단위 테스트의 대부분의 개념에 공통되는 것은 소프트웨어의 개별 구성 요소를 분리 한 테스트라는 개념입니다. 구성 요소 란 무엇입니까? 정의는 다양하지만 단위 테스트에서는 일반적으로 시스템의 가장 원자적인 동작 단위에 관심이 있습니다. 절차 코드에서 단위는 종종 기능입니다. 객체 지향 코드에서 단위는 클래스입니다.

getter와 setter를 찾는 OOP를 사용하면 단위는 클래스 이며 반드시 개별 메소드는 아닙니다. 입니다.

좋은 시험은 무엇입니까?

모든 요구 사항 및 테스트는 Hoare 로직 의 형식을 따릅니다 .

{P} C {Q}

어디:

  • {P}전제 조건입니다 ( 주어진 )
  • C트리거 조건입니다 ( when )
  • {Q}사후 조건이다 ( then )

그런 다음 최대가됩니다.

구현이 아닌 테스트 동작

C, 사후 조건을 달성하는 방법을 테스트하지 말고 {Q}그 결과인지 확인해야합니다 C.

OOP에 관해서 C는 클래스입니다. 따라서 내부 효과는 테스트하지 말고 외부 효과 만 테스트해야합니다.

왜 빈 게터와 세터를 따로 테스트하지 않는가?

게터와 세터는 약간의 로직을 포함 할 수 있지만, 너무 오래이 논리는 외부 효과가 없습니다 - 그들을 만드는 콩 접근 (2) 자를 ) 테스트는 객체 내부를 살펴 봐야합니다.

따라서 빈 getter와 setter를 분리해서 테스트해서는 안됩니다. 이것은 나쁘다 :

Describe 'LineItem class'

    Describe 'setVAT()'

        it 'should store the VAT rate'

            lineItem = new LineItem()
            lineItem.setVAT( 0.5 )
            expect( lineItem.vat ).toBe( 0.5 )

경우 만 setVAT예외를 슬로우 해주기 때문에, 해당 테스트는 적절한 것 외부 효과.

게터와 세터를 어떻게 테스트해야합니까?

이러한 효과가 나중에 영향을 주더라도 외부에 영향을 미치지 않으면 객체의 내부 상태를 변경하는 지점은 거의 없습니다.

따라서 세터와 게터에 대한 테스트는 내부 메소드가 아닌 이러한 메소드의 외부 효과에 대해 고려해야합니다.

예를 들면 다음과 같습니다.

Describe 'LineItem class'

    Describe 'getGross()'

        it 'should return the net time the VAT'

            lineItem = new LineItem()
            lineItem.setNet( 100 )
            lineItem.setVAT( 0.5 )
            expect( lineItem.getGross() ).toBe( 150 )

당신은 자신에게 생각할 수 있습니다 :

잠깐만, 우리는 getGross()여기서 테스트 하지 않습니다 setVAT() .

그러나 setVAT()오작동 인 경우 해당 테스트는 모두 동일하게 실패합니다.

1 Feathers, M., 2004. 레거시 코드로 효과적으로 작업합니다. 프렌 티스 홀 프로페셔널.

2 Martin, RC, 2009. 깨끗한 코드 : 민첩한 소프트웨어 장인의 핸드북. 피어슨 교육.


13

속성에 대한 정당한 이유가 있지만 속성을 통해 멤버 상태를 노출하는 것은 잘못된 디자인이라는 일반적인 객체 지향 디자인의 믿음이 있습니다. 공개 폐쇄 원칙에 대한 Robert Martin의 기사 는 속성이 커플 링을 권장하므로 클래스를 수정하지 못하도록 제한하는 기능을 제한함으로써이를 확장합니다. 속성을 수정하면 클래스의 모든 소비자도 변경해야합니다. 그는 멤버 변수를 노출하는 것이 반드시 나쁜 디자인 일 필요는 없으며 스타일이 좋지 않을 수도 있다고 규정합니다. 그러나 속성이 읽기 전용 인 경우 남용 및 부작용이 적습니다.

단위 테스트에 제공 할 수있는 가장 좋은 방법은 가능한 한 많은 속성을 보호하거나 내부적으로 만드는 것입니다. 이렇게하면 게터와 세터에 대한 바보 같은 테스트를 작성하지 말고 커플 링을 방지 할 수 있습니다.

입력 필드에 바인딩 된 ViewModel 속성과 같이 읽기 / 쓰기 속성을 사용해야하는 분명한 이유가 있습니다.

보다 실질적으로, 단위 테스트는 공개 방법을 통해 기능성을 주도해야합니다. 테스트중인 코드가 해당 속성을 사용하는 경우 코드 적용 범위가 무료입니다. 이러한 속성이 코드 커버리지로 강조 표시되지 않는 경우 다음과 같은 가능성이 매우 높습니다.

  1. 속성을 간접적으로 사용하는 테스트가 누락되었습니다
  2. 속성이 사용되지 않습니다

getter 및 setter에 대한 테스트를 작성하면 적용 범위가 잘못되어 실제로 기능적 동작에 의해 특성이 사용되는지 여부를 판별 할 수 없습니다.


12

게터 및 / 또는 세터 의 순환 복잡도 가 1 (일반적으로있는 경우)이면 대답은 '아니오'입니다.

따라서 100 % 코드 적용이 필요한 SLA가 없다면 소프트웨어의 중요한 측면을 테스트하는 데 신경 쓰지 말고 집중하십시오.

PS 속성이 같은 것처럼 보일 수있는 C #과 같은 언어에서도 게터와 세터를 구분해야합니다. 세터 복잡도는 게터보다 높을 수 있으므로 단위 테스트의 유효성을 검사합니다.


4
게터에 대한 방어 카피를 테스트해야하지만
Sled

8

유머러스하면서도 현명한 선택 : Testivus의 길

"지금 할 수있는 테스트를 작성하십시오"

숙련 된 테스터이고 소규모 프로젝트 인 경우 게터 / 세터 테스트가 과도 할 수 있습니다. 그러나 단위 테스트 방법을 배우기 시작하거나 이러한 게터 / 세터에 로직 ( setMom()예 : @ArtB의 예) 이 포함되어 있으면 테스트를 작성하는 것이 좋습니다.


1
귀하의 링크는 실제로 다음을 가리켜 야합니다 : The Testivus
JJS

2

이것은 실제로 우리 팀과 I 사이의 최근 주제였습니다. 우리는 80 %의 코드 범위를 촬영합니다. 우리 팀은 게터와 세터가 자동으로 구현되고 컴파일러가 기본 코드를 생성한다고 주장합니다. 이 경우 생성 된 코드가 방해가되지 않기 때문에 컴파일러에서 생성 한 코드를 테스트하는 것은 실제로 의미가 없습니다. 우리는 비동기 메소드에 대해서도이 논의를했으며,이 경우 컴파일러는 뒤에서 많은 코드를 생성합니다. 이것은 다른 경우이며 우리가 테스트하는 것입니다. 긴 답변을 짧게 작성하고 팀에 가져와 테스트 할 가치가 있는지 스스로 결정하십시오.

또한 코드 커버리지 보고서를 사용하는 경우 [ExcludeFromCodeCoverage] 특성을 추가하면됩니다. 우리의 솔루션은 getter 및 setter를 사용하는 속성이 있거나 속성 자체에 모델이있는 모델에 이것을 사용하는 것입니다. 이렇게하면 코드 범위 백분율을 계산하는 데 사용한다고 가정하고 코드 범위 보고서가 실행될 때 총 코드 범위 %에 영향을 미치지 않습니다. 행복한 테스트!


2

내 생각에 코드 범위는 당신이 다루어야 할 기능을 놓쳤는 지 확인하는 좋은 방법입니다.

당신이 그것을 꽤 채색하여 수동으로 적용 범위를 검사 할 때, 평범한 게터와 세터는 테스트 할 필요가 없다고 주장 할 수 있습니다 (항상 그래도).

프로젝트에서 코드 적용률 만 확인하면 80 %와 같은 테스트 적용률은 의미가 없습니다. 모든 논리적 부분을 테스트하고 중요한 부분을 잊을 수 있습니다. 이 경우 100 %만이 모든 중요한 코드 및 모든 비논리적 코드를 테스트했음을 의미합니다. 99.9 %가 되 자마자 무언가를 잊었다는 것을 알게됩니다.

그건 그렇고 : 코드 범위는 클래스를 완전히 (단위) 테스트했는지 확인하는 최종 점검입니다. 그러나 100 % 코드 적용 범위가 반드시 클래스의 모든 기능을 실제로 테스트했음을 의미하지는 않습니다. 따라서 단위 테스트는 항상 클래스의 논리에 따라 구현되어야합니다. 결국 당신은 당신이 아무것도 잊었는지 확인하기 위해 적용 범위를 실행합니다. 당신이 그것을 올바르게했을 때, 당신은 처음으로 100 %를 쳤다.

한 가지 더 : 최근 네덜란드의 대형 은행에서 일하면서 소나가 100 % 코드 범위를 나타내는 것을 알았습니다. 그러나 나는 무언가가 빠져 있다는 것을 알았습니다. 파일 당 코드 적용 비율을 검사하면 파일이 낮은 비율로 표시됩니다. 전체 코드 기본 백분율은 하나의 파일이 백분율을 99.9 %로 표시하지 않은 크기입니다. 그래서 당신은 이것을 찾고 싶을 것입니다 ...



1

예 : getter / setter 메소드의 오류는 자동으로 몰래 들어가서 추악한 버그를 일으킬 수 있습니다.

나는 이것과 다른 테스트를 더 쉽게하기 위해 lib를 작성했다. JUnit 테스트에서 작성해야 할 유일한 것은 다음과 같습니다.

        assertTrue(executor.execute(Example.class, Arrays.asList( new DefensiveCopyingCheck(),
            new EmptyCollectionCheck(), new GetterIsSetterCheck(),
            new HashcodeAndEqualsCheck(), new PublicVariableCheck())));

-> https://github.com/Mixermachine/base-test


0

그렇습니다. 특히 가져올 항목이 추상 클래스에서 서브 클래스 된 클래스의 객체 인 경우 특히 그렇습니다. IDE는 특정 속성이 초기화되지 않았다는 경고 메시지를 표시하거나 표시하지 않을 수 있습니다.

그리고 분명히 관련이없는 테스트가 a NullPointerException와 충돌 하고 gettable 속성이 실제로 처음에 도착하지 않는다는 것을 알아내는 데 시간이 걸립니다.

그럼에도 불구하고 여전히 생산 문제를 발견하는 것만 큼 나쁘지는 않습니다.

모든 추상 클래스에 생성자가 있는지 확인하는 것이 좋습니다. 그렇지 않은 경우 게터 테스트를 통해 문제를 경고 할 수 있습니다.

프리미티브의 getter 및 setter와 관련하여 질문은 다음과 같습니다. 프로그램을 테스트 중입니까, 아니면 JVM 또는 CLR을 테스트 중입니까? 일반적으로 JVM은 테스트 할 필요가 없습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.