왜 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.