[java] Mockito와 JMockit 비교-Mockito가 JMockit보다 더 나은 투표를받은 이유는 무엇입니까? [닫은]

내 프로젝트에 사용할 모의 프레임 워크를 조사 중이며 JMockitMockito 로 좁혔습니다 .

Mockito 가 Stackoverflow에서 ” Java를위한 최고의 모의 프레임 워크 “로 선정 되었음을 알았습니다 . JMockit 의 ” Mocking Tool Comparision Matrix ” 의
기능을 비교할 때 JMockit 에는 여러 가지 기능이있는 것으로 보입니다 .

누구든지 Mockito가 할 수있는 일 에 대한 특정 정보 (의견이 아님)가 있습니까? JMockit 으로 달성 할 수없고 그 반대의 경우도 마찬가지입니까?



답변

2019 년 9 월 업데이트 : Spring Boot에서 기본적으로 지원되는 유일한 모의 프레임 워크Mockito 입니다. Spring을 사용한다면 대답은 아주 분명합니다.


나는 경쟁이 사이라고 말하고 싶지만 JMockitPowerMock , 다음 Mockito .

“일반”jMock과 EasyMock은 프록시와 CGLIB 만 사용하고 최신 프레임 워크처럼 Java 5 계측을 사용하지 않기 때문에 그대로 둡니다.

jMock은 또한 4 년 넘게 안정적인 릴리스가 없었습니다. jMock 2.6.0은 RC1에서 RC2로 이동하는 데 2 ​​년이 걸렸고 실제로 출시되기까지 2 년이 더 걸렸습니다.

프록시 및 CGLIB 대 계측 관련 :

(EasyMock 및 jMock)은 인터페이스 구현이 필요한 java.lang.reflect.Proxy를 기반으로합니다. 또한 CGLIB 하위 클래스 생성을 통해 클래스에 대한 모의 객체 생성을 지원합니다. 그렇기 때문에 상기 클래스는 최종 클래스가 될 수 없으며 재정의 가능한 인스턴스 메서드 만 모의 될 수 있습니다. 그러나 가장 중요한 것은 이러한 도구를 사용할 때 테스트중인 코드의 종속성 (즉, 테스트중인 특정 클래스가 의존하는 다른 클래스의 개체)을 테스트에 의해 제어해야 모의 인스턴스가 클라이언트에 전달 될 수 있다는 것입니다. 그 종속성의. 따라서 종속성은 단위 테스트를 작성하려는 클라이언트 클래스의 new 연산자로 간단히 인스턴스화 될 수 없습니다.

궁극적으로 기존 모킹 도구의 기술적 한계는 프로덕션 코드에 다음과 같은 설계 제한을 부과합니다.

  1. 테스트에서 모의해야 할 각 클래스는 별도의 인터페이스를 구현하거나 최종적이지 않아야합니다.
  2. 테스트 할 각 클래스의 종속성은 구성 가능한 인스턴스 생성 방법 (팩토리 또는 서비스 로케이터)을 통해 얻거나 종속성 주입을 위해 노출되어야합니다. 그렇지 않으면 단위 테스트가 종속성의 모의 구현을 테스트중인 단위에 전달할 수 없습니다.
  3. 인스턴스 메서드 만 모의 처리 할 수 ​​있으므로 단위 테스트 할 클래스는 종속성에 대한 정적 메서드를 호출 할 수 없으며 생성자를 사용하여 인스턴스화 할 수 없습니다.

위의 내용은 http://jmockit.org/about.html 에서 복사되었습니다 . 또한 자체 (JMockit), PowerMock 및 Mockito를 여러 가지 방식으로 비교합니다.

이제 PowerMock, jEasyTest 및 MockInject 사이에서 기존의 한계를 극복 한 Java 용 모의 도구가 있습니다. JMockit의 기능 세트에 가장 가까운 것은 PowerMock이므로 여기서 간단히 평가할 것입니다 (게다가 다른 두 가지는 더 제한적이며 더 이상 적극적으로 개발되지 않는 것 같습니다).

JMockit 대 PowerMock

  • 우선, PowerMock은 조롱을위한 완전한 API를 제공하지 않지만 대신 현재 EasyMock 또는 Mockito 일 수있는 다른 도구에 대한 확장으로 작동합니다. 이는 해당 도구의 기존 사용자에게 분명히 이점입니다.
  • 반면 JMockit은 주 API (기대)가 EasyMock 및 jMock과 유사하지만 완전히 새로운 API를 제공합니다. 이것은 더 긴 학습 곡선을 생성하지만 JMockit은 더 간단하고 일관 적이며 사용하기 쉬운 API를 제공 할 수 있습니다.
  • JMockit Expectations API와 비교할 때 PowerMock API는보다 “낮은 수준”이므로 사용자가 테스트를 위해 준비해야하는 클래스를 파악하고 지정해야합니다 (@PrepareForTest ({ClassA.class, …}) 주석 사용). ) 및 프로덕션 코드에 존재할 수있는 다양한 종류의 언어 구조를 처리하기 위해 특정 API 호출이 필요합니다. 정적 메서드 (mockStatic (ClassA.class)), 생성자 (suppress (constructor (ClassXyz.class))), 생성자 호출 ( expectNew (AClass.class)), 부분 모의 (createPartialMock (ClassX.class, “methodToMock”)) 등
  • JMockit Expectations를 사용하면 모든 종류의 메서드와 생성자는 @Mocked 주석의 정규 표현식을 통해 지정된 부분 모의 또는 기록 된 기대없이 멤버를 “모의 해제”하여 순전히 선언적인 방식으로 조롱됩니다. 즉, 개발자는 테스트 클래스에 대해 일부 공유 “모의 필드”를 선언하거나 개별 테스트 메서드에 대해 일부 “로컬 모의 필드”및 / 또는 “모의 매개 변수”를 선언합니다 (이 마지막 경우 @Mocked 주석은 종종 필요).
  • Equals 및 hashCode, 재정의 된 메서드 등에 대한 지원과 같이 JMockit에서 사용할 수있는 일부 기능은 현재 PowerMock에서 지원되지 않습니다. 또한 테스트 코드 자체가 실제 구현 클래스에 대한 지식 없이는 테스트가 실행될 때 지정된 기본 유형의 인스턴스 및 모의 구현을 캡처하는 JMockit의 기능에 해당하는 기능이 없습니다.
  • PowerMock은 모의 클래스의 수정 된 버전을 생성하기 위해 사용자 지정 클래스 로더 (일반적으로 테스트 클래스 당 하나)를 사용합니다. 사용자 정의 클래스 로더를 많이 사용하면 타사 라이브러리와 충돌이 발생할 수 있으므로 테스트 클래스에 @PowerMockIgnore ( “package.to.be.ignored”) 주석을 사용해야하는 경우가 있습니다.
  • JMockit ( “Java 에이전트”를 통한 런타임 계측)에서 사용하는 메커니즘은 더 간단하고 안전하지만 JDK 1.5에서 개발할 때 JVM에 “-javaagent”매개 변수를 전달해야합니다. JDK 1.6+ (이전 버전에 배포하더라도 항상 개발에 사용할 수 있음)에서는 이러한 요구 사항이 없습니다. JMockit은 Attach API를 사용하여 요청시 Java 에이전트를 투명하게로드 할 수 있기 때문입니다.

최근의 또 다른 조롱 도구는 Mockito입니다. 이전 도구 (jMock, EasyMock)의 한계를 극복하려고 시도하지는 않지만 mock으로 새로운 스타일의 동작 테스트를 도입합니다. JMockit은 Verifications API를 통해이 대체 스타일도 지원합니다.

JMockit 대 Mockito

  • Mockito는 레코드 (when (…)) 및 검증 (verify (…)) 단계 사이에서 코드를 분리하기 위해 API에 대한 명시 적 호출에 의존합니다. 즉, 테스트 코드에서 모의 ​​객체를 호출하려면 모의 API에 대한 호출도 필요합니다. 또한 이것은 종종 반복적 인 when (…) 및 verify (mock) … 호출로 이어집니다.
  • JMockit을 사용하면 유사한 호출이 없습니다. 물론 새로운 NonStrictExpectations () 및 new Verifications () 생성자 호출이 있지만 테스트 당 한 번만 발생하며 (일반적으로) 모의 메서드 및 생성자에 대한 호출과 완전히 분리됩니다.
  • Mockito API는 모의 메서드 호출에 사용되는 구문에 여러 가지 불일치를 포함합니다. 기록 단계에서는 when (mock.mockedMethod (args)) …와 같은 호출이 있지만 확인 단계에서는 동일한 호출이 verify (mock) .mockedMethod (args)로 작성됩니다. 첫 번째 경우에는 mockedMethod에 대한 호출이 모의 객체에서 직접 이루어지고 두 번째 경우에는 verify (mock)에 의해 반환 된 객체에서 수행됩니다.
  • 모의 메소드에 대한 호출은 항상 모의 인스턴스 자체에서 직접 이루어지기 때문에 JMockit에는 이러한 불일치가 없습니다. (한 가지 예외 만 있습니다 : 동일한 모의 인스턴스에 대한 호출을 일치시키기 위해 onInstance (mock) 호출이 사용되어 onInstance (mock) .mockedMethod (args)와 같은 코드가 생성됩니다.하지만 대부분의 테스트에서는이를 사용할 필요가 없습니다. )
  • 메서드 체이닝 / 래핑에 의존하는 다른 조롱 도구와 마찬가지로 Mockito는 void 메서드를 스터 빙 할 때 일관성없는 구문을 실행합니다. 예를 들어 when (mockedList.get (1)). thenThrow (new RuntimeException ()); void가 아닌 메서드의 경우 doThrow (new RuntimeException ()). when (mockedList) .clear (); 공허한 사람을 위해. JMockit에서는 항상 동일한 구문입니다. mockedList.clear (); 결과 = new RuntimeException () ;.
  • Mockito 스파이를 사용할 때 또 다른 불일치가 발생합니다. 스파이를받은 인스턴스에서 실제 메서드를 실행할 수있는 “모의”입니다. 예를 들어, 스파이가 빈 목록을 참조하는 경우 when (spy.get (0)). thenReturn ( “foo”)를 작성하는 대신 doReturn ( “foo”). when (spy) .get ( 0). JMockit에서 동적 모의 기능은 스파이와 유사한 기능을 제공하지만 실제 메서드는 재생 단계에서만 실행되므로이 ​​문제가 없습니다.
  • Java 용 첫 번째 모의 API 인 EasyMock 및 jMock에서 초점은 (기본적으로) 예기치 않은 호출을 허용하지 않는 모의 객체에 대한 모의 메서드의 예상 호출 기록에 전적으로 초점을 맞추 었습니다. 이러한 API는 또한 예기치 않은 호출을 허용하는 모의 객체에 대해 허용 된 호출 기록을 제공하지만 이는 2 급 기능으로 취급되었습니다. 또한 이러한 도구를 사용하면 테스트중인 코드가 실행 된 후 모의 호출을 명시 적으로 확인할 수있는 방법이 없습니다. 이러한 모든 확인은 암시 적으로 자동으로 수행됩니다.
  • Mockito (그리고 Unitils Mock에서도)에서는 반대의 관점을 취합니다. 테스트 중에 발생할 수있는 모의 객체에 대한 모든 호출은 기록 여부에 관계없이 허용되며 예상되지 않습니다. 확인은 테스트중인 코드가 실행 된 후에 명시 적으로 수행되며 자동으로 수행되지 않습니다.
  • 두 가지 접근 방식 모두 너무 극단적이며 결과적으로 최적이 아닙니다. JMockit Expectations & Verifications는 개발자가 각 테스트에 대해 엄격 (기본적으로 예상 됨) 및 비 엄격 (기본적으로 허용됨) 모의 호출의 최상의 조합을 원활하게 선택할 수있는 유일한 API입니다.
  • 더 명확하게 말하면 Mockito API에는 다음과 같은 단점이 있습니다. 무효가 아닌 모의 메서드에 대한 호출이 테스트 중에 발생했는지 확인해야하지만 테스트에 반환 유형의 기본값과 다른 메서드의 반환 값이 필요한 경우 Mockito 테스트에 중복 코드가 있습니다. 기록 단계에서 when (mock.someMethod ()). thenReturn (xyz) 호출, 검증 단계에서 verify (mock) .someMethod (). JMockit을 사용하면 엄격한 기대치를 항상 기록 할 수 있으므로 명시 적으로 확인할 필요가 없습니다. 또는 기록 된 비 엄격 기대에 대해 호출 횟수 제약 (times = 1)을 지정할 수 있습니다 (Mockito를 사용하면 이러한 제약은 verify (mock, constraint) 호출에서만 지정 될 수 있음).
  • Mockito는 순서에 따른 검증과 전체 검증 (즉, 모의 객체에 대한 모든 호출이 명시 적으로 검증되었는지 확인)에 대해 잘못된 구문을 가지고 있습니다. 첫 번째 경우에는 추가 객체를 생성하고 이에 대한 검증을 호출해야합니다. InOrder inOrder = inOrder (mock1, mock2, …). 두 번째 경우에는 verifyNoMoreInteractions (mock) 또는 verifyZeroInteractions (mock1, mock2)와 같은 호출이 이루어져야합니다.
  • JMockit을 사용하면 new Verifications () 대신 new VerificationsInOrder () 또는 new FullVerifications () (또는 두 요구 사항을 결합하는 new FullVerificationsInOrder ())를 작성하면됩니다. 관련된 모의 객체를 지정할 필요가 없습니다. 추가 조롱 API 호출이 없습니다. 보너스로 주문 된 확인 블록 내에서 unverifiedInvocations ()를 호출하면 Mockito에서는 불가능한 주문 관련 확인을 수행 할 수 있습니다.

마지막으로 JMockit Testing Toolkit은 완전하고 정교한 개발자 테스트 솔루션을 제공하기 위해 다른 모의 툴킷보다 넓은 범위야심 찬 목표를 가지고 있습니다. 인위적인 제한없이 조롱을위한 좋은 API는 생산적인 테스트 생성에 충분하지 않습니다. IDE에 구애받지 않고 사용하기 쉬우 며 잘 통합 된 코드 커버리지 도구도 필수적이며, 이것이 JMockit 커버리지가 제공하고자하는 것입니다. 테스트 스위트의 크기가 커짐에 따라 더욱 유용해질 개발자 테스트 도구 세트의 또 다른 부분은 프로덕션 코드에 대한 현지화 된 변경 후에 테스트를 점진적으로 재실행하는 기능입니다. 이것은 Coverage 도구에도 포함되어 있습니다.

(허용됨, 소스가 편향 될 수 있지만 음 …)

나는 JMockit 과 함께 가라고 말할 것입니다 . 사용하기 쉽고 유연하며 테스트 할 클래스를 제어 할 수없는 (또는 호환성 이유 등으로 인해 중단 할 수없는) 어려운 경우와 시나리오에서도 거의 모든 경우에 작동합니다.

JMockit에 대한 나의 경험은 매우 긍정적이었습니다.


답변

나는 Mockito와 JMockit 모두와 함께 일했으며 그들에 대한 나의 경험은 다음과 같습니다.

  • Mockito :

    • 암시 적 모킹 (-> 사용성이 더 좋지만 모의에서 허용되지 않는 메서드 호출을 감지하지 못할 위험이 있음)
    • 명시 적 검증
  • EasyMock :

    • 노골적인 조롱
    • 암시 적 검증
  • JMockit :

    • 둘 다 지원
  • 또한 JMockit의 다른 이점 :

    • 정적 메서드 / 생성자 등을 조롱하는 경우 (예 : UT없이 매우 오래된 레거시 코드베이스를 확장하는 경우) 1) Powermock 확장이있는 Mockito / EasyMock 또는 2) Jmockit
    • 내장 커버리지 보고서

저는 개인적으로 JMockit을 선호하는데, 기능이 더 풍부하고 유연하다고 생각하지만 조금 더 가파른 학습 곡선이 필요합니다. 일반적으로 동일한 모의 효과를 얻는 방법은 여러 가지가 있으며 모의를 디자인 할 때 더 많은주의가 필요합니다.


답변

Deencapsultation.class 의 리플렉션 라이브러리 때문에 jMockit 사용 합니다. 나는 실제로 Mockito의 스타일을 좋아하지만 제한된 테스트 프레임 워크가 그것을 얻을 수 있도록 내 코드 변경을 거부하고 내 API를 혼란스럽게 만듭니다. 그리고 저는 제 모든 코드를 테스트하는 것을 좋아합니다. 그래서 private 메서드를 쉽게 테스트 할 수없는 프레임 워크는 제가 사용하고 싶은 것이 아닙니다.

이 기사 에 흔들렸다

(확실히 큰) 학습 곡선 이후 jMockit은 이제 모의를위한 주요 단위 테스트 프레임 워크입니다.


답변

레거시 코드베이스를 쉽게 테스트하기 위해 (많은 정적 메서드 호출 등) JMockit은 매우 유용했습니다. [ 내 블로그 기사 에 대한 뻔뻔한 플러그 ]


답변

개인적으로 EasyMock을 선호합니다 .
멋지고, 보통이고, 엄격한 조롱 컨트롤 사이를 전환하는 기능은 제가 가장 좋아하는 기능 중 하나입니다.


답변