Mock测试

本文详细介绍了Mock测试的概念,包括在单元测试中使用Mockito模拟复杂依赖和未完成模块的场景。通过一个具体的SourceController测试案例,展示了如何使用Mockito进行接口测试,包括Mockito.when和Mockito.doAnswer的使用方法,帮助读者理解如何有效地进行单元测试和接口测试。
摘要由CSDN通过智能技术生成

Mock测试

定义

对于单元测试,对于一些不容易构造获取的对象,或者对于尚未开发的模块,创建一个mock对象模拟对象的行为

何时使用mock测试

1、被依赖的对象构造复杂

class A 依赖 class B

class B 依赖 class Cclass D

class C 依赖 ...

class D 依赖 ...
    
比如我们想对A进行测试,而此时需要构造大量的class B、C、D等依赖对象,他们的构造过程复杂,此时可以利用mock构造虚拟的B、C、D对象对我们需要的A进行相关的测试

2、被依赖的模块尚未开发完成,而被测对象需要依赖模块的返回值进行测试

class AController{
    @Autowire
    private AService service;
    
    public void find(){
        service.findAll();
    }
}

此时我们的AService尚未构造成功,但我们需要对Acontroller进行测试,我们可以用mock虚拟构造Aservice并构造返回值

如何使用mock进行测试

有一个controller代码如下

import com.zhongkai.errorbook.service.SourceService;
import com.zhongkai.errorbook.util.Result;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import java.util.Map;

/**
 * @author 17715
 * 用来查询以及增加错题来源
 */
@RestController
@RequestMapping("/source")
public class SourceController {

    @Autowired
    private SourceService sourceService;

    @GetMapping("/selectSource")
    public Result selectSource(String openid){
        return sourceService.selectSource(openid);
    }
}

此时需要对这个selectController的selectSource进行相关的测试

假设此时的sourceService还没开发完毕

此时的mock测试类为

import com.zhongkai.errorbook.mapper.SourceMapper;
import com.zhongkai.errorbook.service.SourceService;
import com.zhongkai.errorbook.service.impl.SourceServiceImpl;
import com.zhongkai.errorbook.util.CodeMsg;
import com.zhongkai.errorbook.util.Result;
import org.apache.commons.collections4.Get;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultMatcher;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.test.web.servlet.result.StatusResultMatchers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;

import java.sql.ResultSet;

/**
 * @author simba@onlying.cn
 * @date 2021/4/28 14:08
 */
@RunWith(SpringRunner.class)
public class SourceControllerTest {
    /**
     * MockMvc主要进行相关的web controller的测试
     */
    private MockMvc mockMvc;
    /**
     * @Mock表示对SourceController依赖的对象进行注入
     */
    @Mock
    private SourceService service;
    /**
     * @InjectMocks表示将@Mock的对象注入进SourceController
     */
    @InjectMocks
    private SourceController sourceController;

    /**
     * 进行相关的MockMvc的初始化
     */
    @Before
    public void init() {
        MockitoAnnotations.initMocks(this);
        mockMvc = MockMvcBuilders.standaloneSetup(sourceController).build();
    }

    /**
     * 通过Mockmvc进行相关的接口请求
     * @throws Exception
     */
    @Test
    public void selectTest() throws Exception {
        String openid = "1235664";
        //构造service的虚拟对象,模拟返回值
        Mockito.when(service.selectSource(openid)).thenReturn(new Result(
                new CodeMsg(111, "测试成功")));
        //模拟对controller接口的调用,并进行相关的参数校验
        this.mockMvc.perform(MockMvcRequestBuilders.get("/source/selectSource").content(openid)
        ).andExpect(MockMvcResultMatchers.status().isOk());
    }

    /**
     * 不利用MockMvc进行相关的测试,而是直接调用controller进行相关的测试
     */
    @Test
    public void selectTest2() {
        String openid = "1235664";
        Result result = new Result(new CodeMsg(111, "测试成功"));
         /**
         * 此处也可以用 Mockito.when(service.selectSource(Mockito.anyString())).thenReturn(result);
         * Mockito可以生成任意的字符串、数字、或者复制对象(用any(Class class))生成
         */
        Mockito.when(service.selectSource(openid)).thenReturn(result);
        Result result1 = sourceController.selectSource(openid);
        Assert.assertEquals(result1, result);
    }
}

展示了两种测试controller的方法,对于接口的测试建议还是用第一种进行相关测试

Mockito.when与Mockito.doAnswer的讲解

Mockito.when

  Mockito.when(service.selectSource(openid)).thenReturn(new Result(
                new CodeMsg(111, "测试成功")));

when与thenReturn进行搭配,表示当执行某个方法的时候返回某个返回值,这个返回值在thenReturn中定义,常用于知道返回值的时候,且此时的参数信息不需要额外处理

Mockito.doAnswer

  Mockito.doAnswer(new Answer() {
            @Override
            public Object answer(InvocationOnMock invocationOnMock) throws Throwable {
                NirvanaWizardProductDO wizardProductDO = invocationOnMock.getArgument(0);
                wizardProductDO.setId(1);
                return null;
            }
        }).when(service).updateStatus(wizardProductDO);

doAnswer表示当service执行updateStatus时返回answer方法返回的值,常用来处理参数信息需要额外处理的时候。

在Java中,Mock测试是一种常见的测试方法,用于模拟对象或服务器的行为,以便进行自己想要的测试Mock测试主要有两种场景。 第一种场景是Mock一个对象,通过写入预期的值来进行测试。这种方法主要适用于单元测试,即针对特定语言开发的程序,必须使用基于该语言的Mock方案来实现。例如,Mockito是一种针对Java的Mock框架,适用于单元测试。\[1\] 第二种场景是Mock一个服务器,构造一个虚假的服务来返回预期的结果,以进行测试。这种方法主要适用于接口测试和性能测试Mock方案与程序使用的语言无关,可以使用Java、Python等语言来实现。例如,可以搭建一个Mock服务器来模拟接口的行为,适用范围没有限制。\[2\] 在Java中进行Mock测试时,可以使用一些框架和注解来简化测试代码的编写。例如,使用Mockito框架可以使用注解@RunWith(MockitoJUnitRunner.class)和@Mock来模拟对象的行为,使用@InjectMocks来注入被测试对象。下面是一个示例代码: ```java @RunWith(MockitoJUnitRunner.class) @PrepareForTest(MyService.class) public class UserServiceTest { @InjectMocks private MyService myService; @Mock private MyRepository myRepository; @Mock private YourRepository yourRepository; @Test public void testInjectMocks() { System.out.println(myService.getMyRepository().getClass()); } } ``` 在这个示例中,使用了@RunWith(MockitoJUnitRunner.class)注解来运行测试,并使用@Mock注解来模拟对象的行为。@InjectMocks注解用于注入被测试对象。\[3\] 总结起来,Java中的Mock测试是一种常见的测试方法,可以用于模拟对象或服务器的行为,以进行自己想要的测试。可以使用Mockito等框架和注解来简化测试代码的编写。 #### 引用[.reference_title] - *1* *2* [走进Java接口测试Mock(概念篇)](https://blog.csdn.net/zuozewei/article/details/84892008)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] - *3* [JAVA测试类注解以及Mock测试](https://blog.csdn.net/m0_67793822/article/details/127387243)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v91^insertT0,239^v3^insert_chatgpt"}} ] [.reference_item] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值