programing

모의 개체-MockIto Initialising

newsource 2022. 8. 12. 23:29

모의 개체-MockIto Initialising

많은 방법 모의 개체 MockIto을 사용하여 초기화하기 위한 것.이 중에서 무엇이 최선의 방법?

1.

 public class SampleBaseTestCase {

   @Before public void initMocks() {
       MockitoAnnotations.initMocks(this);
   }
@RunWith(MockitoJUnitRunner.class)
mock(XXX.class);

만약 어떤 다른 새로운 방법보다 낫다 날을 제시해 보시오...

그 모크스 초기화하려면 주자 또는을 사용하여.MockitoAnnotations.initMocks니 엄격하게 등가 해결책입니다.그 Mockito의 javadoc부터.JUnitRunner:

그래서 MockitoAnnotations.initMocks(Object)의 명확한 사용할 필요는 없다JUnit 45선수 모크스 모의와 주석이 달린 초기화합니다.Mocks 각 시험 법 전에 초기화됩니다.


번째 해결 방법(「」를 ).MockitoAnnotations.initMocks러너( 「러너」)가 이미 되어 있는 할 수 .SpringJUnit4ClassRunner★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★

해결 (「」를 사용).MockitoJUnitRunner)가 더 내가 가장 좋아하는 명작이야.이 코드가 더 간단하다.Runner를 사용하면 프레임워크 사용 현황을 자동으로 확인할 수 있는 큰 이점이 있습니다(이 답변에서는 @David Wallace에 의해 설명됨).

두 솔루션 모두 테스트 방법 간에 모크(및 스파이)를 공유할 수 있습니다.와 조합하면 유닛테스트를 매우 빠르게 작성할 수 있습니다.보일러 플레이트 모킹 코드가 줄어들어 테스트 판독이 쉬워집니다.예를 들어 다음과 같습니다.

@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에 설명된 대로 "self contained test"를 가질 수 있습니다.

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가 어떻게 동작하는지 명확하게 설명합니다(How my my my my my my my my )ArticleManager인스턴스화 됩니다).보일러 플레이트 코드는 없습니다.

단점: 테스트가 자체 억제되지 않고 코드의 번거로움이 줄어듭니다.

현재(v1.10.7 현재) Mock을 인스턴스화하는 네 번째 방법은 MockitoRule이라고 불리는 JUnit4 규칙을 사용하고 있습니다.

@RunWith(JUnit4.class)   // or a different runner of your choice
public class YourTest
  @Rule public MockitoRule rule = MockitoJUnit.rule();
  @Mock public YourMock yourMock;

  @Test public void yourTestMethod() { /* ... */ }
}

JUnit은 @Rule로 주석을 단 TestRule의 서브클래스를 검색하여 Runner가 제공하는 테스트 문을 래핑합니다.결과적으로 @Before 메서드, @After 메서드를 추출할 수 있습니다.또한 규칙에 래퍼를 캐치할 수도 있습니다.테스트 내에서 예상한 방식으로 이러한 항목과 상호 작용할 수도 있습니다.예외는 그렇다.

Mockito Rule은 Mockito와 거의 똑같이 동작합니다.JUnitRunner파라미터화(테스트 컨스트럭터가 여러 번 테스트를 실행할 수 있도록 인수를 사용할 수 있음)나 Robollectric의 테스트 러너(클래스로더가 Android 네이티브클래스를 대체할 Java를 제공할 수 있음)와 같은 다른 어떤 러너도 사용할 수 있습니다.따라서 최신 JUnit 및 Mockito 버전에서 사용할 수 있는 유연성이 대폭 향상되었습니다.

요약:

  • Mockito.mock(): 또는 직접 주석 지원이나 사용 검증 없이 직접 호출합니다.
  • MockitoAnnotations.initMocks(this) 지원, 석석지 、 용용검검없없 。
  • MockitoJUnitRunner: 주석 지원 및 사용 검증. 단, 해당 주자를 사용해야 합니다.
  • MockitoRule: JUnit Runner 입니다.

다음 항목도 참조하십시오.JUnit @Rule의 구조

Mockito Annotations & Runner는 위에서 충분히 논의되었으므로, 저는 사랑받지 못하는 사람들을 위해 기부하겠습니다.

XXX mockedXxx = mock(XXX.class);

이 테스트를 사용하는 이유는 좀 더 알기 쉽기 때문입니다.또한 (적절한 금지 사항이 아닌) 단위 테스트에서는 멤버 변수를 사용하지 않는 것이 좋습니다.테스트는 가능한 한 멤버 변수를 스스로 억제하는 것이 좋습니다.

이것을 하는 깔끔한 방법이 있다.

  • 유닛 테스트의 경우는, 다음과 같이 실시할 수 있습니다.

    @RunWith(MockitoJUnitRunner.class)
    public class MyUnitTest {
    
        @Mock
        private MyFirstMock myFirstMock;
    
        @Mock
        private MySecondMock mySecondMock;
    
        @Spy
        private MySpiedClass mySpiedClass = new MySpiedClass();
    
        // It's gonna inject the 2 mocks and the spied object per reflection to this object
        // The java doc of @InjectMocks explains it really well how and when it does the injection
        @InjectMocks
        private MyClassToTest myClassToTest;
    
        @Test
        public void testSomething() {
        }
    }
    
  • 편집: 통합 테스트인 경우 이 작업을 수행할 수 있습니다(스프링에서는 이 방법으로 사용할 수 없습니다).다른 러너로 모크를 초기화할 수 있다는 것을 보여주기만 하면 됩니다).

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration("aplicationContext.xml")
    public class MyIntegrationTest {
    
        @Mock
        private MyFirstMock myFirstMock;
    
        @Mock
        private MySecondMock mySecondMock;
    
        @Spy
        private MySpiedClass mySpiedClass = new MySpiedClass();
    
        // It's gonna inject the 2 mocks and the spied object per reflection to this object
        // The java doc of @InjectMocks explains it really well how and when it does the injection
        @InjectMocks
        private MyClassToTest myClassToTest;
    
        @Before
        public void setUp() throws Exception {
              MockitoAnnotations.initMocks(this);
        }
    
        @Test
        public void testSomething() {
        }
    }
    

JUnit 5 Jupiter의 경우 "RunWith"가 제거되었습니다. 이제 "@ExtendWith" 주석을 사용하여 Extensions를 사용해야 합니다.

@ExtendWith(MockitoExtension.class)
class FooTest {

  @InjectMocks
  ClassUnderTest test = new ClassUnderTest();

  @Spy
  SomeInject bla = new SomeInject();
}

1. Mockito Annotations.open Mocks() 사용:

MockitoAnnotations.initMock()되고 Mockito 2로 됩니다.MockitoAnnotations.openMocks()' 3요.3'입니다.MockitoAnnotations.openMocks()는 메서드의 합니다.AutoClosable테스트 후 리소스를 닫는 데 사용할 수 있습니다.은 '보다 낫다'를 사용한 입니다.MockitoAnnotations.openMocks().

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;


class MyTestClass {

    AutoCloseable openMocks;

    @BeforeEach
    void setUp() {
        openMocks = MockitoAnnotations.openMocks(this);
        // my setup code...
    }

    @Test
    void myTest() {
        // my test code...
        
    }

    @AfterEach
    void tearDown() throws Exception {
        // my tear down code...
        openMocks.close();
    }

}

2. @ExtendWith(MockitoExtension.class) 사용:

JUnit5 @RunWith을 사용하다은 '보다 낫다'를 사용한 입니다.@ExtendWith:

@ExtendWith(MockitoExtension.class)
class MyTestClass {

    @BeforeEach
    void setUp() {
        // my setup code...
    }

    @Test
    void myTest() {
        // my test code...

    }

    @AfterEach
    void tearDown() throws Exception {
        // my tear down code...
    }

}

의 " " "Mockito그 방법은 폐지되었다.

권장되는 방법은 사용입니다.

전용 러너/내선번호를 사용할 수 없는 경우 사용할 수 있습니다.

기타 답변은 훌륭하며, 필요한 경우 자세한 내용이 포함되어 있습니다.
그 외에 TL을 추가하고 싶습니다.DR:

  1. 사용하는 것을 선호하다
    • @RunWith(MockitoJUnitRunner.class)
  2. (이미 다른 주자를 사용하고 있기 때문에) 사용할 수 없는 경우
    • @Rule public MockitoRule rule = MockitoJUnit.rule();
  3. (2)와 비슷하지만 더 이상 사용하지 마십시오.
    • @Before public void initMocks() { MockitoAnnotations.initMocks(this); }
  4. 하나의 테스트에서만 모형을 사용하고 동일한 테스트 클래스의 다른 테스트에 노출하지 않으려면 다음과 같이 하십시오.
    • X x = mock(X.class)

(1) 및 (2) 및 (3)은 상호 배타적이다.
(4)는 다른 것과 조합하여 사용할 수 있다.

언급URL : https://stackoverflow.com/questions/15494926/initialising-mock-objects-mockito