ความแตกต่างระหว่าง @Mock, @MockBean และ Mockito.mock ()


148

เมื่อสร้างการทดสอบและจำลองการอ้างอิงความแตกต่างระหว่างสามแนวทางนี้คืออะไร?

  1. @MockBean:

    @MockBean
    MyService myservice;
  2. @Mock:

    @Mock
    MyService myservice;
  3. Mockito.mock ()

    MyService myservice = Mockito.mock(MyService.class);

คำตอบ:


200

ห้องสมุด Mockito ธรรมดา

import org.mockito.Mock;
...
@Mock
MyService myservice;

และ

import org.mockito.Mockito;
...
MyService myservice = Mockito.mock(MyService.class);

มาจากไลบรารี Mockito และเทียบเท่ากับฟังก์ชัน
อนุญาตให้ล้อเลียนชั้นเรียนหรืออินเทอร์เฟซและบันทึกและตรวจสอบพฤติกรรมในชั้นเรียน

วิธีการใช้คำอธิบายประกอบสั้นกว่าจึงเป็นที่นิยมและมักเป็นที่ต้องการ


โปรดทราบว่าในการเปิดใช้งานคำอธิบายประกอบ Mockito ระหว่างการดำเนินการทดสอบ MockitoAnnotations.initMocks(this)จะต้องมีการเรียกใช้วิธีการแบบคงที่
เพื่อหลีกเลี่ยงผลข้างเคียงระหว่างการทดสอบขอแนะนำให้ทำก่อนการทดสอบแต่ละครั้ง:

@Before 
public void initMocks() {
    MockitoAnnotations.initMocks(this);
}

อีกวิธีหนึ่งในการเปิดใช้งานคำอธิบายประกอบ Mockito คือการใส่คำอธิบายประกอบในคลาสทดสอบด้วยการ@RunWithระบุMockitoJUnitRunnerว่าทำงานนี้และสิ่งที่มีประโยชน์อื่น ๆ :

@RunWith(org.mockito.runners.MockitoJUnitRunner.class)
public MyClassTest{...}

ห้องสมุด Spring Boot ที่ห่อห้องสมุด Mockito

นี่คือคลาส Spring Boot :

import org.springframework.boot.test.mock.mockito.MockBean;
...
@MockBean
MyService myservice;

ชั้นเรียนรวมอยู่ในspring-boot-testห้องสมุด

มันช่วยให้การเพิ่ม mocks Mockito ApplicationContextในฤดูใบไม้ผลิ
ถ้า bean ที่เข้ากันได้กับคลาสที่ประกาศมีอยู่ในบริบทมันจะถูกแทนที่ด้วยการจำลอง
หากไม่เป็นเช่นนั้นก็เพิ่มการจำลองในบริบทเป็นถั่ว

อ้างอิง Javadoc:

คำอธิบายประกอบที่สามารถใช้เพื่อเพิ่ม mocks ให้กับ Spring ApplicationContext

...

หากถั่วเดี่ยวที่มีอยู่ชนิดเดียวกันที่กำหนดไว้ในบริบทจะถูกแทนที่ด้วยการจำลองหากไม่มีการกำหนด bean ที่มีอยู่จะมีการเพิ่มถั่วใหม่


เมื่อใช้ Mockito แบบคลาสสิก / ธรรมดาและเมื่อใช้@MockBeanจาก Spring Boot?

การทดสอบหน่วยได้รับการออกแบบมาเพื่อทดสอบส่วนประกอบที่แยกออกจากส่วนประกอบอื่น ๆ และการทดสอบหน่วยก็มีข้อกำหนดเช่นกัน: ให้เร็วที่สุดเท่าที่จะเป็นไปได้ในแง่ของเวลาในการดำเนินการเนื่องจากการทดสอบเหล่านี้อาจดำเนินการในแต่ละวันได้หลายสิบครั้งบนเครื่องของผู้พัฒนา

ดังนั้นนี่คือแนวทางง่ายๆ:

ในขณะที่คุณเขียนการทดสอบที่ไม่ต้องการการอ้างอิงใด ๆ จากคอนเทนเนอร์ Spring Boot Mockito แบบคลาสสิก / ธรรมดาเป็นวิธีที่จะปฏิบัติตาม: รวดเร็วและสนับสนุนการแยกส่วนประกอบที่ทดสอบ
หากการทดสอบของคุณจำเป็นต้องพึ่งพาคอนเทนเนอร์ Spring Boot และคุณต้องการเพิ่มหรือเยาะเย้ยถั่วคอนเทนเนอร์อย่างใดอย่างหนึ่ง: @MockBeanจาก Spring Boot เป็นวิธีการ


การใช้งาน Spring Boot โดยทั่วไป @MockBean

ในขณะที่เราเขียนคลาสทดสอบที่มีคำอธิบายประกอบ@WebMvcTest(web test slice)

เอกสาร Spring Bootสรุปได้เป็นอย่างดี:

มัก@WebMvcTestจะถูก จำกัด ไว้ที่คอนโทรลเลอร์เพียงตัวเดียวและใช้ร่วมกับ@MockBeanเพื่อจัดเตรียมการใช้งานจำลองสำหรับผู้ทำงานร่วมกันที่ต้องการ

นี่คือตัวอย่าง:

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;

import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;

@RunWith(SpringRunner.class)
@WebMvcTest(FooController.class)
public class FooControllerTest {

    @Autowired
    private MockMvc mvc;

    @MockBean
    private FooService fooServiceMock;

    @Test
    public void testExample() throws Exception {
         Foo mockedFoo = new Foo("one", "two");

         Mockito.when(fooServiceMock.get(1))
                .thenReturn(mockedFoo);

         mvc.perform(get("foos/1")
            .accept(MediaType.TEXT_PLAIN))
            .andExpect(status().isOk())
            .andExpect(content().string("one two"));
    }

}

4
การใช้ @MockBean จะสร้างสำเนาของ bean และฉีดไปที่ ApplicationContext หรือไม่ หรือถั่วจำลองจะมีวิธีการทั้งหมดเป็นโมฆะ? ถ้าเมธอดทั้งหมดเป็นโมฆะฉันจะทำให้มันเหมือนที่ใช้ @Mock ได้ไหม
Doug

6
ตามที่อธิบายไว้การใช้@MockBeanจะแทนที่ bean ในบริบทของแอปพลิเคชันหาก bean ที่ประกาศประเภทเดียวกันถูกกำหนดไว้แล้วในการกำหนดค่า Spring ของคุณ และการฉีดจะดำเนินการในคลาสที่คุณประกาศ @MockBean.กลไก DI ทำงานในลักษณะนี้: คุณลงทะเบียนอ็อบเจ็กต์ในบริบท DI จากนั้นคุณสามารถฉีดอ็อบเจ็กต์ที่อ้างถึงในบริบท Spring ในคลาสเฉพาะ คุณไม่ฉีดวัตถุในบริบท DI
davidxxx

13

ในตอนท้ายมันง่ายที่จะอธิบาย หากคุณเพียงแค่ดู javadocs ของคำอธิบายประกอบคุณจะเห็นความแตกต่าง:

@ ม็อก: ( org.mockito.Mock)

ทำเครื่องหมายฟิลด์เป็นแบบจำลอง

  • อนุญาตให้สร้างการจำลองชวเลข
  • ลดรหัสการสร้างจำลองซ้ำ ๆ
  • ทำให้คลาสทดสอบอ่านง่ายขึ้น
  • ทำให้ข้อผิดพลาดในการตรวจสอบอ่านง่ายขึ้นเนื่องจากมีการใช้ชื่อฟิลด์เพื่อระบุการจำลอง

@MockBean: ( org.springframework.boot.test.mock.mockito.MockBean)

คำอธิบายประกอบที่สามารถใช้เพื่อเพิ่ม mocks ให้กับ Spring ApplicationContext สามารถใช้เป็นคำอธิบายประกอบระดับชั้นเรียนหรือในเขตข้อมูลใน@Configurationชั้นเรียนหรือชั้นเรียนทดสอบที่เป็น@RunWithSpringRunner

สามารถลงทะเบียน Mocks ได้ตามประเภทหรือชื่อถั่ว ถั่วเดี่ยวที่มีอยู่ประเภทเดียวกันที่กำหนดไว้ในบริบทจะถูกแทนที่ด้วยการจำลองหากไม่มีการกำหนด bean ที่มีอยู่จะมีการเพิ่มถั่วใหม่

เมื่อ@MockBeanถูกนำไปใช้ในฟิลด์เช่นเดียวกับการลงทะเบียนในบริบทของแอปพลิเคชันการจำลองจะถูกแทรกลงในฟิลด์ด้วย

Mockito.mock ()

มันเป็นเพียงการแสดงของไฟล์@Mock.


5
อย่าลืมว่า @Mock ต้องการ MockitoRunner หรือ initMocks ที่เรียกด้วยตนเอง
Florian Schaetz

4
ความแตกต่างเพียงอย่างเดียวระหว่าง@MockBeanและ@Mockสิ่งที่จะฉีดล้อเลียนเข้าไปในSpring ApplicationContextและอื่น ๆ จะไม่?
Doug

3
@ Doug คุณสรุปได้ดี แต่ต้องจำไว้ว่า MockBean เป็นส่วนหนึ่งของ Spring Boot
comiventor
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.