mocks 초기화의 경우 runner 또는를 사용하는 것은 완전히 MockitoAnnotations.initMocks
동등한 솔루션입니다. MockitoJUnitRunner 의 javadoc에서 :
JUnit 4.5 runner initializes mocks annotated with Mock, so that explicit usage of MockitoAnnotations.initMocks(Object) is not necessary. Mocks are initialized before each test method.
첫 번째 솔루션 (사용 MockitoAnnotations.initMocks
)은 이미 특정 러너 (SpringJUnit4ClassRunner
)은 테스트 케이스에서 예 .
두 번째 솔루션 ( MockitoJUnitRunner
)은 더 클래식하고 제가 가장 좋아하는 솔루션 입니다. 코드는 더 간단합니다. 러너를 사용하면 프레임 워크 사용에 대한 자동 유효성 검사의 큰 이점이 있습니다 ( 이 답변 에서 @David Wallace 설명 ).
두 솔루션 모두 테스트 방법간에 모의 (및 스파이)를 공유 할 수 있습니다. 와 함께 사용하면 @InjectMocks
단위 테스트를 매우 빠르게 작성할 수 있습니다. 상용구 모의 코드가 줄어들고 테스트가 더 읽기 쉽습니다. 예를 들면 :
@RunWith(MockitoJUnitRunner.class)
public class ArticleManagerTest {
@Mock private ArticleCalculator calculator;
@Mock(name = "database") private ArticleDatabase dbMock;
@Spy private UserProvider userProvider = new ConsumerUserProvider();
@InjectMocks private ArticleManager manager;
@Test public void shouldDoSomething() {
manager.initiateArticle();
verify(database).addListener(any(ArticleListener.class));
}
@Test public void shouldDoSomethingElse() {
manager.finishArticle();
verify(database).removeListener(any(ArticleListener.class));
}
}
장점 : 코드가 최소화 됨
단점 : 흑 마법. IMO는 주로 @InjectMocks 주석 때문입니다. 이 주석을 사용하면 "코드의 고통 을 덜 수 있습니다." ( @ Brice 의 훌륭한 댓글 참조 )
세 번째 해결책은 각 테스트 방법에 대한 모의를 만드는 것입니다. @mlk 에 의해 설명 된 대로 " 자체 테스트 " 를 가질 수 있습니다 .
public class ArticleManagerTest {
@Test public void shouldDoSomething() {
// given
ArticleCalculator calculator = mock(ArticleCalculator.class);
ArticleDatabase database = mock(ArticleDatabase.class);
UserProvider userProvider = spy(new ConsumerUserProvider());
ArticleManager manager = new ArticleManager(calculator,
userProvider,
database);
// when
manager.initiateArticle();
// then
verify(database).addListener(any(ArticleListener.class));
}
@Test public void shouldDoSomethingElse() {
// given
ArticleCalculator calculator = mock(ArticleCalculator.class);
ArticleDatabase database = mock(ArticleDatabase.class);
UserProvider userProvider = spy(new ConsumerUserProvider());
ArticleManager manager = new ArticleManager(calculator,
userProvider,
database);
// when
manager.finishArticle();
// then
verify(database).removeListener(any(ArticleListener.class));
}
}
장점 : API 작동 방식을 명확하게 보여줍니다 (BDD ...)
단점 : 더 많은 상용구 코드가 있습니다. (모의 생성)
나의 추천 은 타협입니다. @Mock
와 함께 주석을 사용 @RunWith(MockitoJUnitRunner.class)
하되는 사용하지 마십시오 @InjectMocks
.
@RunWith(MockitoJUnitRunner.class)
public class ArticleManagerTest {
@Mock private ArticleCalculator calculator;
@Mock private ArticleDatabase database;
@Spy private UserProvider userProvider = new ConsumerUserProvider();
@Test public void shouldDoSomething() {
// given
ArticleManager manager = new ArticleManager(calculator,
userProvider,
database);
// when
manager.initiateArticle();
// then
verify(database).addListener(any(ArticleListener.class));
}
@Test public void shouldDoSomethingElse() {
// given
ArticleManager manager = new ArticleManager(calculator,
userProvider,
database);
// when
manager.finishArticle();
// then
verify(database).removeListener(any(ArticleListener.class));
}
}
장점 : API 작동 방식을 명확하게 보여줍니다 (내가 ArticleManager
인스턴스화되는 방식). 상용구 코드가 없습니다.
단점 : 테스트는 자체 포함되지 않으며 코드의 고통이 적습니다.