junit-mock测试

        在后台接口开发之后,有必要进行单元测试,可以保证代码的交付质量,同时重构代码得时候,也可以更放心大胆;但是在测试的时候,对于一些不需要的服务,需要使用mock测试来mock函数或者方法;文章做个简单的记录,主要总结下mock,spy的区别,injectMocks的用法,以及PowerMock的使用来解决静态方法的mock;

1.mock和spy的区别

两者都可以注解到某个属性上,区别是用mock注解标注的变量,在调用时,除mock之外的其他方法不会进行调用的,只有声明的mock方法会直接返回给定的值;比如说mock标注在“serviceA”上,同时mock了serviceA中的fun1,如果在测试过程中调用了serviceA的fun2,那么是不会执行fun2的方法的;调用fun1会直接返回mock的返回结果;

spy注解的变量,根据声明的两种方式,当使用doReturn().when时,不进入方法体中调用;而使用when().thenReturn这种方式时,会进行到方法体执行,最后返回声明的结果;如果没有声明方法,那么spy会调用真实的函数的执行流程;下面通过个例子来说明下

定义个类,具体如下所示

public class Main {
 
    public String fun(String s) {
        System.out.println(s + " : fun");
        fun1(s);
        fun2(s);
        return null;
    }
 
    public void fun1(String s) {
        System.out.println(s + " : fun1");
    }
 
    private void fun2(String s) {
        System.out.println(s + " : fun2");
    }
 
    public int getVal(){
        return 5;
    }
}

先使用@Spy注解

import org.junit.Before;
import org.junit.Test;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;

import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doReturn;
public class MainTest {

    @Spy
    private Main mainClass;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        doReturn("SSS").when(mainClass).fun(anyString());
    }

    @Test
    public void test() {
        String aaa = mainClass.fun("aaa");
        System.out.println(aaa);
    }
}

使用doReturn().when方法来mock fun函数的返回结果;然后执行 测试test方法,返回结果,打印出sss

SSS

这里说明这种方式没有执行fun函数的内部;

然后修改下mock的声明方式,其它代码不动,修改如下

public class MainTest {

    @Spy
    private Main mainClass;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        when(mainClass.fun(anyString())).thenReturn("SSS");
    }

    @Test
    public void test() {
        String aaa = mainClass.fun("aaa");
        System.out.println(aaa);
    }
}

执行结果如下所示

 : fun
 : fun1
 : fun2
SSS

说明这种声明的方式,会进入到方法体内部执行,最后再返回结果;


下面再看看mock的测试

public class MainTest {

    @Mock
    private Main mainClass;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
        doReturn("SSS").when(mainClass).fun(anyString());
    }

    @Test
    public void test() {
        String aaa = mainClass.fun("aaa");
        System.out.println(aaa);
    }

}

返回结果SSS,说明mock的方法会直接返回;不会进入方法内部;

下面把mock的声明去掉,如下所示

public class MainTest {

    @Mock
    private Main mainClass;

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

    @Test
    public void test() {
        String aaa = mainClass.fun("aaa");
        System.out.println(aaa);
    }
}

这里会打印null,因为mock的类的方法不会调用的,只有声明的mock方法会直接返回结果;如果改成@Spy来注解,那么会调用真实的方法执行的;这也是mock和spy的区别;

2.InjectMocks

标注为mock或者spy的类可以注入到添加了InjectMocks的类中;举个例子,Service调用Repository中的方法进行数据库操作,我们要mock respository向数据库插入数据的操作,那么就可以

public Class MainTest{

    @InjectMocks
    private MyService service;

    @Mock
    private Repository repository;

}

这样service中调用的就是mock的repository中的方法了;但是有个问题,如果service中注入其他的服务,那么其他的服务都是null;需要通过ReflectionTestUtils.setField注入对应的属性才可以;而且InjectMocks和Autowired添加到同一个属性上,有时会存在InjectMock失败的情况,但是InjectMocks失败是没有通知的,这点需要注意下;

3.静态方法的mock

mockito缺点是无法对静态的方法进行mock测试,静态方法的测试需要引入powermock;

testCompile "org.mockito:mockito-core:2.8.9"
testCompile "org.powermock:powermock-api-mockito2:1.7.1"
testCompile "org.powermock:powermock-module-junit4:1.7.1"

对应的需要引入的jar如图所示,同时需要导入的注解需要进行下面的修改

@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(SpringRunner.class)
@PowerMockIgnore({"javax.management.*", "javax.net.ssl.*"})
@PrepareForTest(UserEntityRoleContext.class)
@SpringBootTest(classes = CrmApp.class)
PowerMockito.mockStatic(UserEntityRoleContext.class);
        PowerMockito.when(UserEntityRoleContext.getRoles(any())).thenReturn(new HashSet<>(Arrays.asList(new String[]{"aaa", "bbb"})));

mock的时候使用上面的方式来mock静态方法;

 

https://www.baeldung.com/mockito-annotations

https://blog.csdn.net/qq_30141957/article/details/81273829

https://blog.csdn.net/Aeroleo/article/details/49946999?locationNum=14&fps=1

https://www.jianshu.com/p/adee7d28cb59

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
使用JUnit+Mock进行自动化测试,可以按照以下步骤进行: 1. 创建一个测试类,使用JUnitMockito等工具进行测试。 ```java @RunWith(MockitoJUnitRunner.class) public class UserControllerTest { @Mock private UserService userService; @InjectMocks private UserController userController; private MockMvc mockMvc; @Before public void setUp() { mockMvc = MockMvcBuilders.standaloneSetup(userController).build(); } @Test public void testGetUserById() throws Exception { User user = new User(); user.setId(1L); user.setName("Test"); user.setAge(18); Mockito.when(userService.getUserById(1L)).thenReturn(user); mockMvc.perform(MockMvcRequestBuilders.get("/users/{id}", 1L)) .andExpect(MockMvcResultMatchers.status().isOk()) .andExpect(MockMvcResultMatchers.jsonPath("$.id").value(1L)) .andExpect(MockMvcResultMatchers.jsonPath("$.name").value("Test")) .andExpect(MockMvcResultMatchers.jsonPath("$.age").value(18)); } } ``` 在这个例子中,使用@RunWith和@Mock注解来配置测试环境,使用@InjectMocks注解来注入需要测试的UserController对象,使用@Before注解来配置MockMvc对象,使用Mockito.when和MockMvc.perform等方法来进行测试。 2. 运行测试用例,查看测试结果。 在Eclipse、IntelliJ IDEA等IDE中,可以右键点击测试类并选择Run As JUnit Test来运行测试用例。测试结果将会在控制台中输出。 在这个例子中,UserController中有一个getUserById方法,用于获取ID为1的用户信息。在测试用例中,使用Mockito.when方法来模拟UserService的getUserById方法的返回值,使用MockMvc.perform方法发送GET请求,并使用MockMvcResultMatchers.jsonPath和MockMvcResultMatchers.status等方法来验证返回结果的正确性。注意,这个例子使用了MockMvcBuilders.standaloneSetup方法来配置MockMvc对象,表示不依赖于Spring容器进行测试。如果需要依赖于Spring容器进行测试,可以使用@SpringBootTest注解和WebMvcTest注解等方法进行配置。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值