2009-07-29 6 views
15

어떻게 Java에서 정적 메서드를 쉽게 조롱합니까?Java (jUnit4)에서 정적 메서드를 쉽게 조롱 할 수 있습니다

나는 내가 리팩터링 더 단위 테스트 할 수 없습니다 내 서비스를 호출 할 필요가 정적 방법을 제어하지 않는 스프링 2.5의 JUnit 4.4

@Service 
public class SomeServiceImpl implements SomeService { 

    public Object doSomething() { 
     Logger.getLogger(this.class); //a static method invoked. 
     // ... 
    } 
} 

을 사용하고 있습니다. 예를 들어 Log4J Logger을 사용했지만 실제 정적 메서드는 비슷합니다. 정적 방법을 변경하는 옵션이 아닙니다. 나는 자바에서 비슷한 일을 어떻게

def mockedControl = mockFor(Logger) 
mockControl.demand.static.getLogger{Class clazz-> … } 
… 
mockControl.verify() 

:

Grails의 작업을하고, 내가 좋아하는 뭔가를 사용하여 사용 해요?

+0

SomeServiceImpl 구현을 변경할 수 있습니까? –

+0

신경 쓰지 마라, Jon Skeet이 방금 내가 생각한 것을 게시했다. 자랑스러워! (Jon Skeet hehe와 같은 생각) –

+0

예 SomeServiceImpl을 변경할 수는 있지만 왜해야합니까? 여분의 간접 참조가 필요한 이유는 무엇입니까? –

답변

0

기본적으로 Java + Spring 2.5에서이 작업을 수행하는 쉬운 방법은 없습니다 & 현재 JUnit 4.4입니다.

정적 호출을 리팩토링하고 추상화 할 수는 있지만 리팩토링하는 코드는 내가 찾던 솔루션이 아닙니다.

JMockit은 작동하는 것처럼 보이지만 Spring 2.5 및 JUnit 4.4와 호환되지 않습니다.

+2

PowerMock이 제안되었으며 정적 메서드를 모방 할 수 있으므로 쉬운 방법이 있습니다 – Richard

+0

PowerMock은 심각한 메모리 누수가 있습니다. 이는 Maven 플러그 인을 사용할 때 Jenkins 빌드의 메모리 사용 및 지속 시간을 확인한 후 발견 한 것이며, 이는 빌드 품질을 보장하기 위해 자동으로 단위 테스트를 실행합니다. 이것이 PowerMock이 나쁜 선택 인 이유입니다. – Igor

+0

체크 아웃 https://blog.jayway.com/2014/11/29/using-another-junit-runner-with-powermock/ @RunWith (PowerMockRunner.class)를 수행 한 다음 @PowerMockRunnerDelegate (SpringJUnit4ClassRunner)에 위임 할 수 있습니다. .수업). 물론 이것은 최신 버전으로 작업해야합니다. – Yasin

14

호출 코드를 제어 할 수 없다는 것을 의미합니까? 왜냐하면 에서까지 정적 메서드를 호출하지만 구현 자체는 호출하지 않기 때문에 쉽게 테스트 할 수 있습니다. 정적 메서드와 동일한 서명을 사용하여 단일 메서드로 종속성 인터페이스를 만듭니다. 프로덕션 구현에서는 정적 메서드를 호출하지만, 현재 정적 메서드를 호출하는 것은 인터페이스를 통해 대신 호출합니다.

그런 다음 정상적인 방법으로 해당 인터페이스를 조롱 할 수 있습니다.

1
public interface LoggerWrapper { 
    public Logger getLogger(Class<?> c); 
    } 
public class RealLoggerWrapper implements LoggerWrapper { 
    public Logger getLogger(Class<?> c) {return Logger.getLogger(c);} 
    } 
public class MockLoggerWrapper implements LoggerWrapper { 
    public Logger getLogger(Class<?> c) {return somethingElse;} 
    } 
0

정적 방법이 좋지 않은 이유 중 하나입니다.

우리는 모의 객체를 설정할 수 있도록 대부분의 공장을 세터로 재구성했습니다. 사실, 우리는 하나의 메소드가 모든 싱글 톤을위한 팩토리로 작동하는 의존성 삽입에 가까운 것을 생각해 냈습니다.

경우에 따라 Logger.setLogger() 메서드를 추가하고 (해당 값을 저장하는 것) 작동 할 수 있습니다. 필요한 경우 로거 클래스를 확장하고 getLogger 메서드를 자신의 것으로 섀도 ​​잉 할 수 있습니다.

4

JMockit 프레임 워크는 정적 메서드의 조롱을 허용합니다.

https://jmockit.dev.java.net/

사실, 그것은 정적 메서드가 완벽하게 유효한 디자인을 선택하고 자신의 사용 때문에 테스트 프레임 워크의 무능력의 제한되어서는 안된다는 포함한 일부 상당히 대담한 주장을한다.

이러한 클레임이 정당화 될 수 있는지 여부에 관계없이 JMockit 프레임 워크 자체는 아직 재미 있지만, 아직 직접 사용해 보지 않았습니다.

+1

정적 방법의 사용은 항상 논쟁의 여지가 있습니다. 그러나 누구든지 final 키워드를 현명하게 사용하는 것에 대해 논쟁을 벌일 수 있습니까? 예를 들어, "Effective Java"책이 그것에 대해 무엇을 말해야한다고 생각해보십시오 (항목 17). –

+1

JMockit 사용을 살펴보면 Spring 2.5.x가 JUnit 4.5 이상과 호환되지 않으며 JMockit이 JUnit 4.4와 호환된다는 것을 알았습니다 (http://jira.springframework.org/browse/SPR-5145 참조). via http://stackoverflow.com/questions/693115/junit4-spring-2-5-asserts-throw-noclassdeffounderror –

+0

그래서 JMockit은 현재 의문입니다. –

0

AspectJ를 사용하여 정적 메서드 호출을 가로 채고 테스트에 유용한 작업을 수행 할 수 있습니다.

+1

어떻게 그럴 수 있습니까? 간단한 예제가 있습니까? –

1

위의 또 다른 대답으로 JMockit은 정적 방법을 모방 할 수 있습니다.

로깅 프레임 워크를 직접 지원할 수도 있습니다. 예를 들어, 다음과 같이 쓸 수 있습니다.


@UsingMocksAndStubs(Log4jMocks.class) 
public class SomeServiceTest 
{ 
    // All test methods in this class will have any calls 
    // to the Log4J API automatically stubbed out. 
} 

그러나 JUnit 4.4 지원은 중단되었습니다. JUnit 3.8, JUnit 4.5+ 및 TestNG 5.8+가 지원됩니다.

4

PowerMock이 있습니다. 테스트 대상 클래스 안에 오브젝트의 인스턴스화를 조롱 할 수도 있습니다. 테스트 된 메소드가 새 Foo()를 호출하면 해당 Foo에 대한 mock 객체를 생성하고 테스트중인 메소드에서이를 대체 할 수 있습니다.

억압 생성자 및 정적 초기화와 같은 것들도 가능합니다. 이 모든 것들은 테스트 할 수없는 코드로 간주되므로 권장되지는 않습니다. 그러나 레거시 코드가 있다면 변경하는 것이 항상 선택 사항은 아닙니다. 당신이 그 위치에 있다면, PowerMock 당신을 도울 수있다.

관련 문제