2010-07-28 4 views
15

많은 응용 프로그램에서 종종 전용 하위 알고리즘 (또는 단순히 잘 정의 된 코드 조각)을 사용하는 알고리즘을 사용합니다.Java에서 로컬 내부 클래스 메서드를 테스트하려면 어떻게해야합니까?

public class OldStyle { 

    public int mainAlg() { 
     int x = subAlg01(); 
     int y = subAlg02(); 
     int z = x * y; 
     return z; 
    } 

    private int subAlg01() { 
     return 3; 
    } 

    private int subAlg02() { 
     return 5; 
    } 
} 

이것은 잘 작동하지만 난 데 좋아하지 않았어요 : 나는 주요 알고리즘을 쓸 때

는 지금까지, 나는 예를 아래 (이전 스타일)처럼 각 하위 알고리즘의 개인 방법을 만들어 사적인 것이라 할지라도 하나의 메소드 (mainAlg)에서만 사용되는 메소드 (subAlg01 및 subAlg02)의 확산.

는 최근에 나는 지역 내부 클래스의 사용을 dicovered 지금 내 예 (NewStyle)입니다 :

public class NewStyle { 

    public int mainAlg() { 
     class Nested { 

      public int subAlg01() { 
       return 3; 
      } 

      public int subAlg02() { 
       return 5; 
      } 
     } 
     Nested n = new Nested(); 
     int x = n.subAlg01(); 
     int y = n.subAlg02(); 
     int z = x * y; 
     return z; 
    } 
} 

나는 그것을 매우 좋아하지만 지금은 다음과 같은 문제가있다 : 어떻게 subAlg01 및 subAlg02 사용 테스트합니까를 JUnit?

덧붙여서 : 나는 일식을 사용하고 있습니다.

도움 주셔서 감사합니다.

편집 : : 내가 더 잘 설명하려고합니다 : 나는 정렬 알고리즘을 가지고 있다고 가정하고 예상대로 실행되는지 테스트하려고합니다. 이 정렬 알고리즘은 클래스 X의 메서드 m에서만 사용됩니다. 클래스 X의 private 메서드로 만들지 만 클래스 X는 일반적으로 정렬과는 아무 관계가 없으므로 클래스 X를 정렬 메서드로 "왜 망칠 수 있습니까?" 그래서 그것을 m 방법 안에 넣습니다. 나중에 약간의 시간이 걸리므로 정렬 알고리즘을 향상시키고 싶습니다. (더 빨리 만들 수 있습니다.)하지만 예상대로 작동하고 있는지 확인하고 싶기 때문에 원래 테스트로 다시 테스트하고 싶습니다.

그게 내가하고 싶은, 어쩌면 해결책이 없는데, 누군가가 나를 도울 수 있기를 바랍니다.

대답 선택 후 편집. 나는 로드니의 대답을 선택했다. 왜냐하면 그의 솔루션이 내가 채택한 솔루션이기 때문이다. 독립 실행 형 도우미 클래스는 하위 메소드가 무엇인지 명확하게 파악하고 테스트 할 수있는 능력을 제공한다 (도움이된다).

+0

I을 이 문제는이 문제와 관련이 없으므로 Eclipse 태그를 제거했습니다. –

답변

10

필리포, 나는이 문제와 몇 가지 대답에 대한 좌절감을 이해합니다. 몇 년 전에 처음 JUnit을 사용하기 시작했을 때 개인 코드를 테스트하기를 원했고 전문가의 말은 바보 같았습니다.

그들이 옳았다는 사실이 밝혀졌습니다.하지만 꽤 많은 테스트를 작성한 후에야 이해할 수있었습니다. 이유는입니다. 같은 과정을 거쳐야하지만, 결국 같은 결론을 내릴 수 있습니다 .-)

어쨌든 상황에 따라 Nested을 적절한 독립 실행 형 클래스로 만들 수 있습니다. 그것은 도우미 클래스라고. 그런 다음 다른 테스트와 독립적으로 직접 테스트를 작성합니다.

그런 다음 NewStyle에 대한 테스트를 작성하고 NewStyle의 동작에만 중점을 둡니다.

(아주 아마도 나는 또한 오히려 NewStyle 내에서 인스턴스화보다 NewStyleNested를 주입 것 -. 즉 NewStyle의 생성자에에게 주장을

을 그럼 난 NewStyle에 대한 테스트를 작성하는 경우 테스트에서 나는 좋겠 또한, 그와 NewStyleNested의 인스턴스에 전달하고 계속한다. 나는 특히 까다로운 생각하면, 내가 Nested에서 인터페이스를 만들 것하고 두 번째 구현을 만들고, 테스트.)

+0

+1은 현재 채택한 솔루션 (독립 실행 형 도우미 클래스)이므로 –

16

전용 멤버 또는 개인 내부 클래스가 아닌 클래스의 공용 인터페이스 만 테스트해야합니다. private 멤버는 구현 세부 사항을 의미하며 클래스의 public 메서드에 의해서만 (직접 또는 간접적으로) 사용됩니다. 따라서 호출자 메소드를 통해 이들을 간접적으로 테스트 할 수 있습니다. 이러한 단위 테스트에서 충분한 세밀도가 없다거나 관심이있는 결과 (일부)를 감지 할 수 없다고 생각되면 디자인에 문제가 있음을 나타냅니다. 클래스가 너무 커서 시도해보십시오. 너무 많은 일을하기 때문에 일부 기능을 별도의 클래스로 추출해야 할 수도 있습니다. 그런 다음 직접 단위 테스트를 수행 할 수 있습니다.

현재 예제에서 내부 클래스 자체에 많은 코드가 포함되어있는 경우이를 최상위 클래스로 변환 한 다음 해당 메서드를 직접 단위 테스트 할 수 있습니다.

(그것을 둘러싸는 클래스의 인스턴스를 참조 할 필요가없는 경우 Btw는 당신의 내면의 클래스는 static을해야합니다.)

+0

안녕하세요, 답장을 보내 주셔서 감사합니다. 나는 이미 너와 같은 많은 대답을 읽었지만 의미는 분명하지 않다. 내가 더 잘 이해하도록 도와 줄 수 있니? 한 번만 사용되는 코드 조각이 있지만 예상 한대로 작동하는지 확인해야합니다. 호는 내가 그것을 성취합니까? 테스트가 나에게 좋은 선택 인 것 같았습니다. –

+0

@Filippo, 내 업데이트 참조. 테스트는 실제로 좋은 선택입니다 - 당신이 생각해 낼 수있는 모든 다른 사용 시나리오를 다루는 테스트를 작성하십시오. 코드 적용 도구를 사용하면 테스트되지 않은 코드 부분을 찾을 수 있습니다. –

+1

@ Péter 정적에 대한 제안에 대해 : 내부 클래스는 정적 로컬 내부 클래스가 될 수 없습니다. –

1

당신은 외부에서 이러한 클래스에 도달 할 수없는, 그래서 JUnit을 그들을 테스트 할 수 없습니다. 테스트하기 위해서는 공개 된 것이 있어야합니다.

+0

올바르지 않습니다. JMockit과 같은 모의 프레임 워크는 사적인 내부 클래스 (private 메소드와 멤버는 물론)를 잘 처리 할 수 ​​있습니다. – jchilders

+1

JMockit은 반사회적으로 장난 꾸러기를하는 경우가 많습니다. –

+0

JMockit (또는 유사한 프레임 워크)이 로컬 내부 클래스의 메서드를 테스트 할 수 있는지 알고 있습니까? –

1

당신은 당신의 코드를 복잡하게 이상하지 않도록해야합니다 단지 당신 때문에

그들이하는 방법이 있다면 당신이 방법을 테스트 할 수 있습니다 방법

귀하의 경우에는

의 확산을 가진 좋아하지 않아

또는 내부 클래스가 절대적으로 필요한 경우 mainAlg() 메서드 외부에 배치하여 전역으로 볼 수 있도록합니다.

public class NewStyle { 

    public int mainAlg() { 

     Nested n = new Nested(); 
     int x = n.subAlg01(); 
     int y = n.subAlg02(); 

     int z = x * y; 
     return z; 
    } 

    class Nested { 

     public int subAlg01() { 
      return 3; 

     } 

     public int subAlg02() { 
      return 5; 
     } 
    } 
} 

이가 다음 new NewStyle().new Nested().subAlg01();

+0

답장을 보내 주셔서 감사합니다. 나는 또한이 솔루션을 시도했지만, 클래스를 보았을 때, 이후 subAlgs가 주요 알고리즘의 일부일 뿐이고 다른 누구도 사용하지 않는다는 명확한 견해가 없기 때문에 광산보다 덜 좋아한다. 그럼에도 불구하고 테스트가 가능합니다. –

+0

new NewStyle(). 새 Nested(). subAlg01(); 확실합니까? 나는 이것을 보지 못했습니다 .../숙고 –

1

흠을 사용하여 호출 할 수 있습니다, 나는 그루비 같은 언어는 종종 자바 단위 테스트를 수행하는 데 사용되는 것을 알고, 투명 private 필드와 메소드에 액세스 할 수 있습니다 .... 그러나 중첩 클래스에 대해서는 잘 모르겠습니다. 나는 왜 이런 종류의 일을하고 싶어하는지 이해할 수있다. 그러나 getter와 setter를 테스트 할 때와 동일한 입장을 취하고 public 메소드를 테스트하는 부작용으로 테스트해야하며, 그렇지 않은 경우 테스트해야한다. 그런 식으로 테스트를 받아야합니다. 그렇다면 왜 그곳에 시작해야할까요?

1

을 문제가 올 때 당신의 내면 클래스의 행동은 wh의 핵심 부분이된다. 메소드에서 다음을 수행합니다. 메소드가 실행 가능한 객체를 세 번째 객체에 전달해야한다고 가정 해 봅니다. 실제로는 별도의 객체가 아니어야하는 내부 클래스입니다.이 경우 적절한 단위 테스트는 실제로 운동이 필요합니다. 내부 클래스는 그 세 번째 객체를 조롱하여 인수를 캡처하여이를 테스트해야한다.

이러한 종류의 문제는 함수 프로그래밍에 대한 지원이 더 많은 언어에서 매우 일반적입니다. 여기서 람다 테스트가 제 3 자에게 전달되는 것은 거의 필수 사항입니다.

하지만 이전에 말했듯이, 내부 클래스가 외부 당사자에 의해 사용되지 않으면 구현 세부 사항 일 뿐이며 별도로 테스트하는 것은 유용하지 않습니다.

1

실제로 로컬 내부 클래스를 테스트 할 수 있습니다. 그러나 인터페이스를 구현해야합니다. 이렇게하면 리플렉션을 통해 로컬 클래스의 인스턴스를 만들어 인터페이스로 전송할 수 있습니다. 당신은 인터페이스 유형이 있으면, 당신은 문제없이 구현하는 코드를 테스트 할 수 있습니다

인터페이스 :

public interface Algorithm { 
    int subAlg01(); 
    int subAlg02(); 
} 

클래스 :

public class NewStyle { 
    public int mainAlg() { 
     class Nested implements Algorithm { 

      public int subAlg01() { 
       return 3; 
      } 

      public int subAlg02() { 
       return 5; 
      } 
     } 
     Nested n = new Nested(); 
     int x = n.subAlg01(); 
     int y = n.subAlg02(); 
     int z = x * y; 
     return z; 
    } 
} 

테스트 :

public class NewStyleTest { 

    @Test 
    public void testLocal() throws ClassNotFoundException, 
      NoSuchMethodException, SecurityException, InstantiationException, 
      IllegalAccessException, IllegalArgumentException, 
      InvocationTargetException { 
     Class<?> forName = Class.forName("NewStyle$1Nested"); 
     Constructor<?> declaredConstructor = forName 
       .getDeclaredConstructor(NewStyle.class); 
     declaredConstructor.setAccessible(true); 
     Algorithm algorithm = (Algorithm) declaredConstructor 
       .newInstance(new NewStyle()); 

     assertEquals(algorithm.subAlg01(), 3); 
     assertEquals(algorithm.subAlg02(), 5); 
    } 
} 
관련 문제