Spring单元测试中@SpyBean和@MockBean区别

Spring单元测试中@SpyBean和@MockBean区别

1、默认行为不同

对于没有用Mockito代理的方法,@SpyBean会调用真实的方法,有返回值的会返回方法的真实返回值(参考下方SpyBeanTest的testException4)。

@MockBean不管有没有用Mockito代理方法,都不会调用真实的方法,有返回值的会返回null(参考下方MockBeanTest的testException4)。

2、Mockito代理的方式不同

@MockBean的代理使用方式:Mockito.when(methodService.testException(anyBoolean())).thenReturn("1","2"...);

@SpyBean的代理使用方式:Mockito.doReturn("1","2"...).when(methodService).testException(anyBoolean());

注:

  • return里的参数:其中"1"表示第一次调用testException的返回值,"2"表示第二次调用testException的返回值,依次类推,只有一个时,每次调用都会返回相同的值。

  • anyBoolean()表示输入参数只要是boolean类型,即会返回指定的模拟值。如果代理方法时写为testException(true),则只有输入参数为true时,才会返回指定的模拟值。

3、@SpyBean和@MockBean应用

(1)@SpyBean使用代理控制返回值

(1)Mockito.doReturn("").when(methodService).testException(false);

不会执行方法体的内容,直接返回doReturn里的指定值""供调用者使用(可参考下方SpyBeanTest的testException1和testException3)。

(2)Mockito.when(methodService.testException(false)).thenReturn("");

会执行方法体的内容,如果抛出异常会直接中断程序执行,否则不管执行结果是什么,会返回thenReturn里的指定值""供调用者使用。(可参考下方SpyBeanTest的testException和testException2)。

(3)Mockito.doNothing().when(methodService).test();

无返回值方法的代理,调用该方法时什么都不做,即不会执行真实的方法(可参考下方SpyBeanTest的testException5)。

(4)Mockito.when(methodService.testException(true)).thenThrow(new NullPointerException());

代理方法testException,使其执行到此方法时抛出自定义异常(可参考下方SpyBeanTest的testException6)。

@MockBean使用代理控制返回值

(1)Mockito.doReturn("").when(methodService).testException(false);

不会执行方法体的内容,但会返回指定值供调用者使用(可参考下方MockBeanTest的testException1和testException3)。

(2)Mockito.when(methodService.testException(false)).thenReturn("");

不会执行方法体的内容,但会返回指定值供调用者使用(可参考下方MockBeanTest的testException和testException2)。

(3)Mockito.doNothing().when(methodService).test();

无返回值方法的代理,调用该方法时什么都不做,即不会执行真实的方法(可参考下方MockBeanTest的testException5)。

(4)Mockito.when(methodService.testException(true)).thenThrow(new NullPointerException());

代理方法testException,使其执行到此方法时抛出自定义异常(可参考下方MockBeanTest的testException6)。

4、@SpyBean和@MockBean应用测试

定义测试类:

package com.example.mock;
​
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
​
@Component
@Slf4j
public class MethodService {
    public String test(boolean throwException) {
        log.info("test start");
​
        String testException = testException(throwException);
​
        log.info("test end");
        return testException;
    }
​
    public String testException(boolean throwException) {
        log.info("testException start");
​
        if (throwException) {
            throw new NullPointerException();
        }
​
        log.info("testException end");
        return "testException";
    }
​
    public void test() {
        log.info("test start");
​
​
        log.info("test end");
    }
​
}

@SpyBean用法

package com.example.mock;
​
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.SpyBean;
​
@SpringBootTest(classes = {MethodService.class})
public class SpyBeanTest {
    @SpyBean //如果没有用Mockito设置代理对象控制某个方法的返回值,会执行方法体的内容,代理对象的使用格式一般为Mockito.doReturn("").when(methodService).testException(true);
    MethodService methodService;
​
    @Test
    void testException() {
        Mockito.when(methodService.testException(false)).thenReturn("");//会执行方法体的内容,不管执行结果是什么,都会返回指定值供调用者使用
        String testException = methodService.test(false);
        Assertions.assertTrue(testException.isEmpty());
    }
​
    @Test
    void testException1() {
        Mockito.doReturn("").when(methodService).testException(false);//不会执行方法体的内容,直接返回指定值供调用者使用
        String testException = methodService.test(false);
        Assertions.assertTrue(testException.isEmpty());
    }
​
    @Test
    void testException2() {
        Mockito.when(methodService.testException(true)).thenReturn("");//会执行方法体的内容,如果抛出异常会直接中断程序执行,否则不管执行结果是什么,会返回指定值供调用者使用
        Assertions.assertThrows(NullPointerException.class, () -> methodService.test(true));
    }
​
    @Test
    void testException3() {
        Mockito.doReturn("").when(methodService).testException(true);//不会执行方法体的内容,直接返回指定值供调用者使用
        String testException = methodService.test(true);
        Assertions.assertTrue(testException.isEmpty());
    }
​
    @Test
    void testException4() { //默认会调用真实的方法,有返回值的返回真实的返回值
        String testException = methodService.test(false);
        Assertions.assertTrue(testException.equals("testException"));
    }
​
    @Test
    void testException5() { //无返回值方法的代理,调用该方法时什么都不做,即不会执行真实的方法
        Mockito.doNothing().when(methodService).test();
        methodService.test();
    }
​
    @Test
    void testException6() {//代理方法testException,使其执行到此方法时抛出自定义异常
        Mockito.when(methodService.testException(true)).thenThrow(new NullPointerException());//会执行方法体的内容,如果抛出异常会直接中断程序执行,否则不管执行结果是什么,会返回指定值供调用者使用
        Assertions.assertThrows(NullPointerException.class, () -> methodService.test(true));
    }
}

@MockBean用法

package com.example.mock;
​
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
​
@SpringBootTest(classes = {MethodService.class})
public class MockBeanTest {
    @MockBean //不管有没有用Mockito设置代理对象返回某个方法的返回值,都不会执行方法体的内容
    MethodService methodService;
​
    @Test
    void testException() {
        Mockito.when(methodService.testException(false)).thenReturn("");//不会执行方法体的内容,但会返回指定值供调用者使用
        String testException = methodService.test(false);
        Assertions.assertEquals(testException, "");
    }
​
    @Test
    void testException1() {
        Mockito.doReturn("").when(methodService).testException(false);//不会执行方法体的内容,但会返回指定值供调用者使用
        String testException = methodService.test(false);
        Assertions.assertEquals(testException, "");
    }
​
    @Test
    void testException2() {
        Mockito.when(methodService.testException(true)).thenReturn("");//不会执行方法体的内容,但会返回指定值供调用者使用
        String testException = methodService.test(true);
        Assertions.assertEquals(testException, "");
    }
​
    @Test
    void testException3() {
        Mockito.doReturn("").when(methodService).testException(true);//不会执行方法体的内容,但会返回指定值供调用者使用
        String testException = methodService.test(true);
        Assertions.assertEquals(testException, "");
    }
​
    @Test
    void testException4() {//没有mock的方法不会执行,默认返回null,如调用test方法时,由于没有代理但有返回值,则返回null
        Mockito.doReturn("").when(methodService).testException(true);//不会执行方法体的内容,但会返回指定值供调用者使用
        String testException = methodService.test(true);
        Assertions.assertEquals(testException, "");
    }
​
​
    @Test
    void testException5() { //无返回值方法的代理,调用该方法时什么都不做,即不会执行真实的方法
        Mockito.doNothing().when(methodService).test();
        methodService.test();
    }
​
    @Test
    void testException6() {//代理方法testException,使其执行到此方法时抛出自定义异常
        Mockito.when(methodService.testException(true)).thenThrow(new NullPointerException());//不会执行方法体的内容,但会返回指定值供调用者使用
        Assertions.assertThrows(NullPointerException.class, () -> methodService.testException(true));
    }
}
​

5、总结

@MockBean对象,则此对象中所有的方法默认都不会被执行 ,有返回值的会返回null。@SpyBean对象,则此对象中所有的方法默认会调用真实的方法,有返回值的会返回方法的真实返回值。@MockBean或@SpyBean的对象,可使用Mockito代理指定方法返回指定指供调用方使用。

六、扩展知识

@Spy和 @SpyBean的区别, @Mock 和 @MockBean的区别

@Mock和@Spy的对象不受Spring管理;@Spy调用真实方法时,其他bean是无法注入的,若要使用注入,需使用@SpyBean; @SpyBean和@MockBean生成的对象受spring管理,相当于自动替换对应类型bean的注入,比如@Autowired等注入 。

注: @MockBean 只能 mock 本地的代码——或者说是自己写的代码,对于储存在库中而且又是以 Bean 的形式装配到代码中的类无能为力。 @SpyBean 解决了 SpringBoot 的单元测试中 @MockBean 不能 mock 库中自动装配的 Bean 的局限 。

  • 6
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值