不可能用 DAO mock 编写集成测试控制器?

Posted

技术标签:

【中文标题】不可能用 DAO mock 编写集成测试控制器?【英文标题】:Impossible to write integration test controller with DAO mock? 【发布时间】:2018-08-09 08:13:30 【问题描述】:

我疯了,我尝试了各种测试运行器和可能注释的所有可能组合进行测试,我需要的最接近的解决方案如下:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = MyApplication.class)
@WebAppConfiguration
public class MyControllerTest 

    MockMvc mockMvc;

    // My DAO is an interface extending JpaRepository
    @Mock
    MyDAO myDAO;

    @Autowired
    WebApplicationContext webApplicationContext;

    @Before
    public void setUp() throws Exception 
        List<MyItem> myItems = new ArrayList()
            // Items init ...
        
        Mockito.when(myDAO.findAll()).thenReturn(myItems);
        /* Other solution I tried with different annotations: 
        * given(myDAO.findAll()).willReturn(myItems);
        * this.mockMvc = MockMvcBuilders.standaloneSetup(myController).build();
        */
        this.mockMvc = webAppContextSetup(webApplicationContext).build();

    

    @After
    public void tearDown() throws Exception 
//        Mockito.reset(myDAO);
    

    @Test
    public void getItems() 
        String res = mockMvc.perform(get("/items"))/*.andExpect(status().isOk())*/.andReturn().getResponse().getContentAsString();
        assertThat(res, is("TODO : string representation of myItems ..."));
        assertNull(res); // For checking change in test functionning
    

我很好地在我的控制器方法中进入调试模式,在服务方法中但是当我看到 DAO 类型时,它不是 Mock 并且 findAll() 总是返回空的 ArrayList(),即使我这样做:

Mockito.when(myDAO.findAll()).thenReturn(myItems);

我没有引发异常,我的 DAO 没有被嘲笑,尽管我找到了所有 tuto,但我不知道该怎么做。 我找到的最接近我需要的 tuto 是 Unit Test Controllers with Spring MVC Test 但还不够,因为他希望将模拟服务注入控制器以测试控制器,我想模拟注入到控制器中的真实服务注入的 DAO(我想测试控制器 + 服务)。

在我看来,我已经通过在测试类上使用注释来做到这一点,该注释指定了 Spring 应用程序必须在测试模式下实例化哪些类以及必须模拟哪些类,但我不记得 '-_ -.

需要你的帮助,这让我发疯了!

非常感谢!!!

【问题讨论】:

尝试在@Test 中写入Mockito.when(myDAO.findAll()).thenReturn(myItems); 而不是在设置中。还要确保myItems 可以在@Test 中访问 【参考方案1】:

我终于做到了(但不满意,因为它不模拟 HSQLDB 数据库,它创建了一个测试数据库),而我想模拟 DAO:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = MySpringApplication.class)
@WebAppConfiguration
public myTestClass 
    MockMvc mockMvc;

    @Autowired
    ItemDAO itemDAO;

    @Autowired
    WebApplicationContext webApplicationContext;

    @Before
    public void setUp() throws Exception 
        this.mockMvc = webAppContextSetup(webApplicationContext).build();
    

    @After
    public void tearDown() throws Exception 
        itemDAO.deleteAll();
    

    @Test
    public void testMethod() 
        // DB init by saving objects: create a item and save it via DAO, use real test DB

        // Only mocking about rest call:
        String res = mockMvc.perform(get("/items")).andExpect(status().isOk()).andReturn().getResponse().getContentAsString();
    

【讨论】:

您需要排除扫描您的 DAO 包,并使用“Mockito.mock(ItemDAO.class)”手动创建一个 DAO bean。【参考方案2】:

对于@Mock 注解,您需要额外的初始化:

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

或者将 runner 更改为 @RunWith(MockitoJUnitRunner... ,但在这种情况下不确定 spring 上下文初始化。

【讨论】:

是的,如果使用另一个跑步者会出现问题(我听说@Delegate注解使用2个跑步者但很复杂)。不幸的是,我已经尝试过了,但没有改变,我的 DAO 没有返回/抛出我告诉它做的事情

以上是关于不可能用 DAO mock 编写集成测试控制器?的主要内容,如果未能解决你的问题,请参考以下文章

集成测试框架

如何使用springboot编写rest控制器、服务和dao层的junit测试用例?

Autofac 集成测试 在 ConfigureContainer 之后进行 Mock 注入

C# - 单元测试,模拟?

Mock测试框架(Mockito为例)

Karma + Jasmine 下 angular.mock.inject 的 TypeScript AngularJS 控制器测试问题