왜 Mockito가 정적 메소드를 조롱하지 않습니까?


267

정적 메소드에 대한 몇 가지 스레드를 읽었으며 정적 메소드의 오용 / 과도한 사용으로 인해 발생할 수있는 문제를 이해한다고 생각합니다. 그러나 정적 메서드를 조롱하기가 어려운 이유는 무엇입니까?

PowerMock과 같은 다른 조롱 프레임 워크가 그렇게 할 수 있지만 왜 Mockito가 할 수 없다는 것을 알고 있습니까?

이 기사를 읽었 지만 저자는 종교적으로 단어에 반대되는 것 같습니다 static. 어쩌면 내 이해력이 떨어질 수도 있습니다.

쉬운 설명 / 링크가 좋을 것입니다.


12
참고 사항 : PowerMock은 모의 객체 라이브러리가 아니며 다른 라이브러리 위에 해당 기능 (모의 정적 및 ctor)을 추가합니다. 직장에서 PowerMock + Mockito를 사용하여 서로 잘 어울립니다.
— Matthias

답변:


238

그 이유는 모의 객체 라이브러리가 일반적으로 런타임에 클래스를 동적으로 생성하여 ( cglib 사용 ) 모의 객체를 생성하기 때문일 수 있습니다 . 즉, 런타임에 인터페이스를 구현하거나 (실수하지 않은 경우 EasyMock 이하는 일) 클래스에서 모의 ​​객체로 상속합니다 (실수하지 않은 경우 Mockito 가하는 일). 상속을 사용하여 재정의 할 수 없으므로 정적 멤버에는 두 가지 방법이 모두 작동하지 않습니다.

정적을 조롱하는 유일한 방법 은 런타임에 클래스의 바이트 코드 를 수정 하는 것입니다. 상속보다 약간 더 복잡하다고 생각합니다.

그게 가치가 있다고 생각합니다.


7
그건 그렇고 생성자를 조롱하는 경우에도 마찬가지입니다. 이것들도 상속을 통해 변경할 수 없습니다.
— Matthias

11
일부 TDD / TBD 지지자들은 정적 메소드와 생성자 조롱이 부족하다는 것을 좋은 것으로 인식한다고 덧붙일 가치가 있습니다 . 그들은 정적 메소드 또는 생성자를 조롱해야 할 때 클래스 디자인이 좋지 않다는 것을 나타냅니다. 예를 들어, 코드 모듈을 조립할 때 순수 IoC 접근 방식을 따를 때, 처음에는 정적 또는 ctor를 조롱 할 필요조차 없습니다 (물론 일부 블랙 박스 구성 요소에 속하지 않는 한). 또한 참조 giorgiosironi.blogspot.com/2009/11/...
— 마티아스

200
나는 조롱 도구가 당신에게 더 나은 것을 알고 있다고 가정하지 않고 필요한 것을 제공해야한다고 생각합니다. 예를 들어, 조롱해야 할 정적 메서드 호출을 사용하는 타사 라이브러리를 사용하는 경우 그렇게 할 수 있으면 좋을 것입니다. 모의 프레임 워크는 나쁜 디자인으로 간주되기 때문에 일부 기능을 제공하지 않는다는 아이디어는 근본적으로 결함이 있습니다.
— Lo-Tan

11
@ Lo-Tan-언어가 당신보다 더 잘 알고 있다고 가정하지 않고 모든 것이 가능해야한다는 것을 말하는 것과 같습니다. 그것은 당신이 부과하는 것처럼 벗겨지기 때문에 당신의 허영입니다. 여기서의 문제는 "안티 / 프로 정적"전투가 명확하지 않으며 프레임 워크도 마찬가지라는 것입니다. 나는 우리 모두가 있어야한다는 데 동의합니다. 그러나 사실 이 분명하면 그 사실 을 강요 하는 틀을 선호합니다 . 그것은 학습의 한 방법입니다-도구는 당신을 추적합니다. 그래서 당신은 스스로 할 필요가 없습니다. 그러나 이제 모든 국수 머리는 소위 "좋은 디자인"을 강요 할 수 있습니다. "기본적으로 결함이있다"
— nevvermind

13
@nevvermind Eh? 고급 언어는 중요한 부분에 집중할 수 있도록 필요한 추상화를 제공하고 도움을주기위한 것입니다. 테스트 라이브러리는 도구입니다. 더 나은 품질과 더 나은 디자인의 코드를 만들기 위해 사용하는 도구입니다. 한계가있는 테스트 / 모의 라이브러리의 요점은 다른 사람의 잘못 설계된 코드를 통합해야 할 때 사용할 수 없다는 것을 의미합니까? 잘 생각하지는 않지만 좋은 언어는 그렇습니다 .
— Lo-Tan

28

정적 메서드를 조롱해야하는 경우 나쁜 디자인에 대한 강력한 지표입니다. 일반적으로 테스트 대상 클래스의 종속성을 조롱합니다. 테스트중인 클래스가 java.util.Math # sin과 같은 정적 메소드를 참조하는 경우 테스트중인 클래스가 정확히이 구현이 필요함을 의미합니다 (예 : 정확도 대 속도). 구체적인 부비동 구현을 추상화하려면 인터페이스가 필요할 것입니다 (어디로 향할 것인지 알 수 있습니까).


3
글쎄, 나는 정적 메소드를 사용하여 "정적 지속성 파사드"와 같은 높은 수준의 추상화를 제공했다. 이러한 파사드는 클라이언트 코드를 ORM API의 복잡성 및 하위 수준 세부 정보에서 멀리 유지하여보다 일관되고 사용하기 쉬운 API를 제공하면서도 많은 유연성을 제공합니다.
— Rogério

그리고 왜 그것을 조롱해야합니까? 정적 메소드에 의존하는 경우 "단위"또는 "모듈"은 클래스 만 아니라 "정적 지속성 파사드"도 포함합니다.
— Jan

88
예를 들어 타사 클래스에있는 정적 메서드를 조롱 해야하는 경우 때로는 선택의 여지가 없습니다.
— Stijn Geukens

6
사실이지만 때로는 싱글 톤을 다룰 수도 있습니다.
— Manu Manjunath

추상화로 해결할 수없는 유일한 생각은 너무 많은 추상화 수준입니다 ... 추상화 레이어를 추가하면 복잡성이 증가하고 종종 불필요합니다. 이 간단한 호출을 단일 클래스로 래핑하여 System.currentTimeMillis ()를 조롱하려고하는 프레임 워크에서 본 예제를 생각합니다. 테스트를 용이하게하기 위해 단순히 메서드를 사용하는 대신 메서드 당 단일 클래스를 사용합니다. 그런 다음 싱글 톤 래퍼 대신 정적 메서드를 직접 호출하는 타사 뎁을 소개하면 테스트가 실패합니다.
— Fr Jeremy Krieg

5

정적 메서드를 조롱 해야하는 경우 코드 냄새라고 생각합니다.

  • 일반적인 기능에 액세스하는 정적 메소드? -> 싱글 톤 인스턴스를 사용하여 주입
  • 타사 코드? -> 자신의 인터페이스 / 델리게이트로 감싸십시오 (필요한 경우 싱글 톤으로 만드십시오)

이 나에게 잔인한 것 같다 유일한 시간, 구아바 같은 libs와,하지만 당신은 논리의 그것의 일부 (Iterables.transform (같은 것들 ..)) 원인 종류 어쨌든이 조롱 할 필요가 없습니다
그런 식으로 자신의 코드 깨끗하게 유지하고 모든 종속성을 깔끔하게 조롱 할 수 있으며 외부 종속성에 대한 부패 방지 계층이 있습니다. 실제로 PowerMock을 보았고 필요한 모든 클래스가 제대로 설계되지 않았습니다. 또한 때때로 PowerMock의 통합으로 심각한 문제가 발생했습니다
(예 : https://code.google.com/p/powermock/issues/detail?id=355 )

추신 : 개인 메소드도 마찬가지입니다. 테스트가 개인 메소드의 세부 사항에 대해 알아야한다고 생각하지 않습니다. 클래스가 너무 복잡하여 개인 메서드를 모방하려는 유혹이 있다면 아마도 해당 클래스를 분할하는 신호 일 것입니다 ...


2
Singleton을 사용하면 모든 종류의 문제가 발생할 수 있습니다. 특히 실제로 둘 이상의 인스턴스가 필요하다는 사실을 깨닫고 이제는 전체 시스템을 리팩토링해야합니다.
— Ricardo Freitas

나는 모든 사람에게 싱글 톤 패턴을 추천한다고 말하지 않았다. 정적 유틸리티 클래스와 동일한 기능을 제공하는 Singleton 중에서 결정해야하는 경우 Singleton을 선택합니다. 그리고 클래스가 싱글 톤이거나 DI 프레임 워크에 의해 제어되지 않으면 클래스 I @Inject SomeDependency과 구성에서 정의 bind(SomeDependency.class).in(Singleton.class)합니다. 따라서 내일 더 이상 싱글 톤이 아니라면 하나의 구성을 변경하면됩니다.
— pete83

@ pete83 나는 당신의 형제를들을 수 있습니다. 그러나 개발자가 테스트 프레임 워크의 디자인 / 한계에 맞게 디자인을 변경 해야하는 테스트 라이브러리 또는 프레임 워크에 문제가 있습니다. 즉, 말 앞에 카트를 두거나 꼬리가 개를 흔드는 IMO입니다.
— 매트 캠벨

1
그 주장은 나에게는 의미가 없습니다. 싱글 톤 패턴은 현재 여러 해 동안 호의를 얻지 못했습니다. "깨끗한"코드는 무엇입니까? I / O 작업을 반환하는 정적 도우미 메서드를 호출하는 클래스 인스턴스 메서드가 있다면 왜 테스트에서 조롱하고 싶지 않습니까? 그리고 저 디자인은 어떻습니까? 모의 정적 메소드를 둘러싼이 모든 핸드링은 더해지지 않습니다. 메소드를 모의하는 것은 테스트하는 것과 반대입니다. 구현 하기가 너무 어려우 면 그냥 말하고
— 끝내

오, 난 모든 사람이 Foo.getInstance()어디서나 전화하는 구식 싱글 톤 패턴에 대해 이야기 한 적이 없어 방금 "정적 메서드는 많은 래퍼 객체를 만들 필요가 없습니다"라는 주장에 대응하기 위해 싱글 톤을 작성했습니다. 또한 개념적으로 싱글 톤의 정적 메소드와 인스턴스 메소드 사이에는 약간의 차이가 있습니다. 단지이 싱글 톤 공동 작업자를 조롱 할 수 없다는 것입니다. 그러나 싱글 톤인지 아닌지는 절대로 내가 만들려고 한 요점이 아니며, 요점은 공동 작업자를 주입하고 조롱하고 테스트가 어려운 경우 정적 메소드를 호출하지 않는 것입니다.
— pete83

4

Mockito는 객체를 반환하지만 정적은 "객체 수준이 아닌 클래스 수준"을 의미하므로 mockito는 정적에 대해 널 포인터 예외를 제공합니다.


0

경우에 따라 정적 메서드는 특히 조롱해야하는 경우 테스트하기 어려울 수 있으므로 대부분의 조롱 프레임 워크에서 지원하지 않습니다. 이 블로그 게시물은 정적 메소드와 클래스를 조롱하는 방법을 결정하는 데 매우 유용하다는 것을 알았 습니다.


1
적절한 모의 API를 사용할 때 정적 메소드를 모의하는 것은 인스턴스가 없기 때문에 인스턴스 모의 메소드를 모의하는 것보다 훨씬 쉽습니다.
— Rogério

이것은 질문 자체에 대한 질문에 답변하는 것과 같으며, 이것이 어려운 이유 이며 이것이 답변이 아닙니다.
— Matthias

40
블로그 게시물은 실제로 사용 되는 정적 메소드에서 클래스를 분리하는 문제를 해결 하는 대신 비용이 많이 드는 해결 방법 (생산 코드 리팩터링)을 권장하기 때문에 하향 조정했습니다 . 실제로 업무를 수행하는 조롱 도구 인 IMO는 어떤 종류의 방법도 차별하지 않습니다. 개발자는 특정 상황에서 정적 방법을 사용하는 것이 한 경로를 강요하지 않고 자유롭게 결정할 수 있어야합니다.
— Rogério
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.