[java] mockito로 최종 수업을 조롱하는 방법

나는 마지막 수업을 가지고 있습니다 :

public final class RainOnTrees{

   public void startRain(){

        // some code here
   }
}

이 클래스를 다음과 같은 다른 클래스에서 사용하고 있습니다.

public class Seasons{

   RainOnTrees rain = new RainOnTrees();

   public void findSeasonAndRain(){

        rain.startRain();

    }
}

JUnit 테스트 클래스 Seasons.java에서 RainOnTrees클래스 를 조롱하고 싶습니다 . Mockito로 어떻게 할 수 있습니까?



답변

최종 / 정적 클래스 / 메소드를 조롱하는 것은 Mockito v2에서만 가능합니다.

gradle 파일에 이것을 추가하십시오 :

testImplementation 'org.mockito:mockito-inline:2.13.0'

Mockito FAQMockito v1에서는 불가능합니다 .

Mockito의 한계는 무엇입니까

  • Java 1.5 이상이 필요합니다

  • 최종 수업을 조롱 할 수 없습니다


답변

Mockito 2는 이제 최종 클래스와 메소드를 지원 합니다!

그러나 현재로서는 “인큐베이팅”기능입니다. Mockito 2의 새로운 기능에 설명 된대로 활성화하려면 몇 가지 단계가 필요합니다 .

최종 클래스와 메서드를 조롱하는 것은 잠복 하고 옵트 인 기능입니다. Java 에이전트 인스 트루먼 테이션과 서브 클래 싱의 조합을 사용하여 이러한 유형의 모형을 구현할 수 있습니다. 이 기능은 현재 메커니즘과 다르게 작동하며 다른 제한 사항이 있으며 경험과 사용자 피드백을 수집하려면이 기능을 명시 적으로 활성화해야 사용할 수 있습니다. src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker단일 행을 포함하는 파일을 작성하여 mockito 확장 메커니즘을 통해 수행 할 수 있습니다 .

mock-maker-inline

이 파일을 만든 후 Mockito는이 새 엔진을 자동으로 사용하며 다음을 수행 할 수 있습니다.

 final class FinalClass {
   final String finalMethod() { return "something"; }
 }

 FinalClass concrete = new FinalClass();

 FinalClass mock = mock(FinalClass.class);
 given(mock.finalMethod()).willReturn("not anymore");

 assertThat(mock.finalMethod()).isNotEqualTo(concrete.finalMethod());

이후 이정표에서 팀은이 기능을 사용하는 프로그래밍 방식을 제공합니다. 우리는 모든 불가능한 시나리오를 식별하고 지원할 것입니다. 지켜봐 주시고이 기능에 대한 귀하의 의견을 알려주십시오!


답변

혼자서 할 수 없으므로 Mockito로 최종 수업을 조롱 할 수 없습니다.

내가하는 일은 최종 클래스를 포장하고 대리자로 사용하기 위해 최종 클래스가 아닌 클래스를 만드는 것입니다. 이것의 예는 TwitterFactory클래스이며, 이것은 내 조롱 가능한 클래스입니다.

public class TwitterFactory {

    private final twitter4j.TwitterFactory factory;

    public TwitterFactory() {
        factory = new twitter4j.TwitterFactory();
    }

    public Twitter getInstance(User user) {
        return factory.getInstance(accessToken(user));
    }

    private AccessToken accessToken(User user) {
        return new AccessToken(user.getAccessToken(), user.getAccessTokenSecret());
    }

    public Twitter getInstance() {
        return factory.getInstance();
    }
}

단점은 많은 상용구 코드가 있다는 것입니다. 장점은 애플리케이션 비즈니스와 관련된 몇 가지 메소드를 추가 할 수 있다는 것입니다 (위의 경우 accessToken 대신 사용자를 가져 오는 getInstance와 같이).

귀하의 경우 최종 RainOnTrees클래스에 위임하는 최종 클래스가 아닌 클래스를 만듭니다 . 또는 최종이 아닌 것으로 만들 수 있다면 더 좋습니다.


답변

gradle 파일에 이것을 추가하십시오 :

testImplementation 'org.mockito:mockito-inline:2.13.0'

이것은 최종 클래스와 함께 mockito를 작동시키는 구성입니다.


답변

Powermock을 사용하십시오. 이 링크는이를 수행하는 방법을 보여줍니다. https://github.com/jayway/powermock/wiki/MockFinal


답변

후속 조치를 취하십시오. 이 줄을 gradle 파일에 추가하십시오 :

testCompile group: 'org.mockito', name: 'mockito-inline', version: '2.8.9'

나는 mockito-core와 mockito-all의 다양한 버전을 시도했습니다. 둘 다 작동하지 않습니다.


답변

final다른 클래스의 확장을 막고 싶기 때문에 당신이 만든 것 같아요 RainOnTrees. 같이 효과적인 자바 제안 (항목 15)을하지 않고 확장을위한 클래스 가까이를 유지하는 또 다른 방법이있다 final:

  1. final키워드를 제거하십시오 .

  2. 생성자 만들기 private . super생성자 를 호출 할 수 없으므로 클래스를 확장 할 수 없습니다 .

  3. 클래스를 인스턴스화하는 정적 팩토리 메소드를 작성하십시오.

    // No more final keyword here.
    public class RainOnTrees {
    
        public static RainOnTrees newInstance() {
            return new RainOnTrees();
        }
    
    
        private RainOnTrees() {
            // Private constructor.
        }
    
        public void startRain() {
    
            // some code here
        }
    }

이 전략을 사용하면 Mockito를 사용하고 상용구 코드를 거의 사용하지 않고 수업을 계속 닫을 수 있습니다.