2016-08-12 3 views
4

현재 SecondClass을 작성해야하며 그렇지 않으면 테스트 할 수 없기 때문에 이러한 종류의 솔루션을 사용하여 작성하기로 결정했습니다.테스트를 위해 추가 생성자를 사용하는 것이 얼마나 좋은가?

@Component 
public class FirstClass { 

    public void doStuff() { 
     System.out.println("First Class stuff!"); 
    } 

} 

@Component 
public class SecondClass { 

    private final Random random; 
    private final FirstClass firstClass; 

    @Autowired 
    public SecondClass(FirstClass firstClass) { 
     this(new Random(), firstClass); 
    } 

    public SecondClass(Random random, FirstClass firstClass) { 
     this.random = random; 
     this.firstClass = firstClass; 
    } 

    public void doOtherStuff() { 
     firstClass.doStuff(); 
     System.out.println("Second Class stuff " + random.nextInt(10)); 
    } 

} 

내 동료는 이런 식으로 해결의 길을 좋아 SecondClass의 구현을 선호하지 않았다 :

@Component 
public class SecondClass { 

    private Random random; 
    private final FirstClass firstClass; 

    @Autowired 
    public SecondClass(FirstClass firstClass) { 
     this.random = new Random(); 
     this.firstClass = firstClass; 
    } 

    public void doOtherStuff() { 
     firstClass.doStuff(); 
     System.out.println("Second Class stuff " + random.nextInt(10)); 
    } 

    public void setRandom(Random random) { 
     this.random = random; 
    } 

} 

내가 Random이의 필요한 부분이라고 생각하기 때문에 나는 이러한 유형의 솔루션에 동의 이 클래스는 실행 시간에 변경되지 않을 것이고 setter는 테스트 목적으로 만 필요하기 때문에 두 생성자가있는 솔루션을 선호합니다.

@Autowired(required = false) 
public SecondClass(FirstClasss firstClass, Random random) { 
    this.random = (random == null ? new Random() : random) 
    ... 
} 

을하지만 그들 모두가 요구했을 경우 것이 바람직 할 것이다, 그래서 생성자 주입 실제로 이상의 구성 요소가있다 :

우리는 또한 생성자의이 종류를 내놓았다.

내가 여기있는 사람이 전에 이런 종류의 경험을했다면 관심이 있습니까? 이 사건에 대해 어떻게 생각하며이 문제를 해결할 더 좋은 방법이 있다면?

+0

제 경험에서 나는 꽤 많은 복합 생성자를 사용했고'final' 필드는 필수적이었습니다 (명백하게 이유가있는 곳은 어디입니까?) –

+0

@PaoloForgia 당신이 경험 한 것에 대해 더 많이 알려 주실 수 있습니까? 여러 생성자가 실제로 도움이되었습니다. – GROX13

+0

http://stackoverflow.com/questions/34571/how-to-test-a-class-that-has-private-methods-fields-or-inner-classes –

답변

2

문제가있어 최종 필드가 생겨납니다. Bob 아저씨를 따라 자유롭게 시험 수업에 글을 쓸 수 있도록 보호하십시오. 당신은 인터페이스를 작성하지 않고 코드를 작성하므로 액세스 수정자는 그다지 중요하지 않으며 패키지 접근을 허용하기 때문에 보호가 잘됩니다.

아니면 당신이 SecondClass에 두 개의 생성자를 선언하고 만 단위 테스트에서 이들 중 하나를 사용하면 하드 배선을, ReflectionUtils.setField

+0

예, 우리는 리플렉션에 대해서도 생각했지만 제 의견으로는 문제를 해결하지 못하고 있습니다. 클래스의 추가 설정자와 거의 같다고 생각합니다. – GROX13

+1

테스트 클래스에서 리플렉션에 문제가있는 사람은 본 적이 없습니다 (물론 과용하지 않는 한 ...) 클래스 내부에서 무작위로 원하는 것을 선택하는 것이 문제입니다. Businesswise, 그것이 최선의 결정이라면 그것이 그렇게되어야합니다. 테스트는 두 번째 관심사이며 테스트 사례만으로 코드를 수정하는 것이 반드시 나쁜 것은 아니지만 가벼운 해킹/반영으로 방지 할 수 있다면 대부분의 사람들은 전혀 문제가 없습니다. –

+0

아니요 저는 반성이나 다른 해결책으로 문제가 생길 것이라고 말하지 않고 있습니다. 나는 이런 종류의 문제를 해결하는 "책으로"어떻게 될지 관심이 있습니다. 왜냐하면 의존성 주입의 가능성이없는 클래스 내에서 새로운 객체를 생성하는 것은 나쁜 생각 일 것이기 때문에 항상 실제 프로젝트에서 이러한 종류의 것들이 발생하고 좋은 아키텍처를 유지하기 위해서는 행동해야한다는 경고 만했기 때문입니다. – GROX13

1

말하여 테스트 케이스에 그들에게 자신을 설정 볼 수 있었다, 그것은한다는 것을 의미 유닛 테스트를위한 생성자는 리플렉션과 같은 당신의 유닛 테스트에 대한 더 적절한 트릭으로 대체되어 random 필드의 값을 설정할 수 있습니다.
피할 수있을 때 단위 테스트 용으로 API를 열면 안됩니다.
선택지가 아닌 경우 단원 테스트를 위해 API를 열어야합니다.

SecondClass이 인스턴스화되는 즉시 random 필드가 읽기 전용이고 알려진 값인 경우 SecondClass에 대한 단일 생성자가 있어야합니다. 그리고 random 필드는 생성자에서 SecondClass의 최종 값이어야합니다.

+0

난 그 문제를 '랜덤'이라는 용어를'doTheStuff' 메쏘드에서 꼭 필요로하고, 네가 읽었을 때'doTheStuff' 메쏘드 만 접근 할 필요는 전혀 없습니다. 단일 생성자에서 무작위 인스턴스 생성을 싫어하는 이유는 그것이 단지 OOP 원칙을 위반한다고 생각하기 때문이며 생성자 클래스에서 인스턴스화하면 유연성이 느슨해집니다. 그러나 이것은 내 의견 일뿐입니다. 단위 테스트는 실제 클라이언트 코드가 수행 할 수있는 것을 나타내는 것이기 때문에 – GROX13

+0

-1입니다. 따라서 단위 테스트를 위해 생성자가 필요한 경우 실제 클라이언트 코드에 유용합니다. 이러한 이유 때문에 반향은 단위 테스트에 좋은 선택이 아닙니다. 단위 테스트는 공개 된 테스트를 거친 API가 완전하고 잘 설계되어 있는지 확인해야합니다. 이를 확인하기 위해 반영이 필요한 경우 API가 완료되지 않았습니다. –

+0

이것은 상태 비 저장 클래스에 대해 완전히 사실입니다. 그것은 주어진 문제가 아닙니다. 결과는 클라이언트에 의해 결정되지 않고 상태 * 및 * 클라이언트에 의해 결정됩니다. 그렇다고 국가가 * public *이라는 의미는 아니며 수정 가능해야합니다. 고유 상태의 가변성을 테스트하려면 해당 상태를 제어해야합니다. 즉, * 액세스 할 수 있거나 리플렉션을 통해 액세스 할 수 있음을 의미합니다. 그러나 상태 저장 객체의 경우 일반적으로 상태가 닫혀 액세스가 가능하지 않아야합니다. –

1

당신은 맞습니다, 친구. 객체 지향 설계에 따라 객체는 해당 생성자 중 하나가 실행 된 후 올바른 상태로 초기화되어야하므로 접근 방식이 적합합니다. 따라서 random 필드가 필요한 경우 모든 생성자에서 초기화해야합니다. 또한 나중에 변경하지 않는 경우 은 최종이어야하며 설정자는 없습니다. 따라서 두 번째 해결책은이 원칙을 위반하기 때문에 올바르지 않습니다.

클라이언트 코드에 어리석은 수 있기 때문에 제 3의 솔루션을 좋아하지 않습니다. 클라이언트가 null 입력 값으로 설정되어 있다고 가정하는 동안 실제로 다른 (제어되지 않은) 값이 대신 사용됩니다.

따라서 SecondClass에 해당 생성자가 필요하면 이동하여 추가하십시오. 왜냐하면 클래스가 테스트 할 수없는 경우 이기 때문에 실행할 수 없습니다.. 테스트를 통해 클래스를 사용할 수 있는지 확인할 수 있습니다.

+0

나는 동의하지 않는다. 단위 테스트는 클라이언트가 응용 프로그램에서 수행하는 작업을 나타내지 않습니다. 그것은 고립 된 방식으로 컴포넌트의 단일 동작을 테스트합니다. 그러나 클라이언트가 사용하는 다른 방식으로 구성 요소를 유닛 테스트하면 속임수를 쓰고 테스트 코드가 실제 동작을 반영하지 않습니다. 게다가 프로덕션 환경에서 사용하지 않으면 단위 테스트 용으로 API를 열지 않아야합니다. 그것은 비합리적입니다. – davidxxx

+0

"단위 테스트는 클라이언트가 응용 프로그램에서 수행하는 작업을 나타내지 않습니다."??? 구성 요소가 유용하고 어떻게 작동하는지 어떻게 알 수 있습니까? –

+0

나는 확인한다. 통합 테스트는 클라이언트가 애플리케이션에서 수행하는 작업을 나타냅니다. 같은 수준이 아닌 다른 개념, 즉 구성 요소와 응용 프로그램을 혼합합니다. – davidxxx

관련 문제