mockito框架使用总结

news2024/11/18 19:42:31

目录

  • 一、mock测试
    • 1.1 mock测试
    • 1.2 相关概念
    • 1.3 mock的好处
  • 二、Mockito框架
    • 2.1 快速入门
    • 2.2 基础语法
      • 2.2.1 生成mock对象
      • 2.2.2 设置预期
      • 2.2.3 检验调用结果
      • 2.2.4 参数匹配器
      • 2.2.5 参数捕捉器
      • 2.2.6 mock静态方法调用
  • 三、集成junit
    • 3.1 集成junit4
    • 3.2 集成junit4+spring
    • 3.1 集成junit4+springboot
    • 3.1 集成junit5
    • 3.1 集成junit5+spring
    • 3.1 集成junit5+springboot

一、mock测试

官网
本文是由博主呕心沥血总结,有极大实用性的生产工具总结,阅读前前收藏。
mockito:一个用来mock测试的工具,能提高提高自测效率。

1.1 mock测试

mock 测试就是在测试过程中,对于某些不容易构造或者不容易获取的对象,用一个虚拟的对象来创建以便测试的测试方法。这个虚拟的对象就是mock对象。mock对象就是真实对象在调试期间的代替品

示例:如下调用链
在这里插入图片描述

我们在测试类 A 时,类 A 需要调用类 B 和类 C,而类 B 和类 C 又需要调用其他类如 D、E、F 等,假如类 D、E、F 构造很耗时又或者调用很耗时的话是非常不便于测试的(比如是 DAO 类,每次访问数据库都很耗时)。所以我们引入 Mock 对象

在这里插入图片描述

如上图,我们将类 B 和类 C 替换成 Mock 对象,在调用类 B 和类 C 的方法时,用 Mock 对象的方法来替换(当然我们要自己设定参数和期望结果)而不用实际去调用其他类。这样测试效率会高很多。

一句话为什么要 Mock:因为我们实际编写程序都不会是一个简单类,而是有着复杂依赖关系的类,Mock 对象让我们在不依赖具体对象的情况下完成测试

1.2 相关概念

  • Mock 对象

mock对象的概念就是我们想要创建一个可以替代实际对象的对象,这个模拟对象要可以通过特定参数调用特定的方法,并且能返回预期结果。


  • Stub(桩)

桩指的是用来替换具体功能的程序段。桩程序可以用来模拟已有程序的行为或是对未完成开发程序的一种临时替代。


  • 设置预期

通过设置预期明确 Mock对象执行时会发生什么:

比如返回特定的值、抛出一个异常、触发一个事件等,又或者调用一定的次数


  • 验证预期的结果

设置预期和验证预期是同时进行的。设置预期在调用测试类的函数之前完成,验证预期则在它之后。

所以,首先你设定好预期结果,然后去验证你的预期结果是否正确


1.3 mock的好处

  1. 提前创建测试(TDD测试驱动开发)(依赖上游服务还没交付,也能进行测试)
  2. 团队可以并行工作(分模块开发时)
  3. 创建一个稳定的验证或者演示程序
  4. 为无法访问的资源编写测试

二、Mockito框架

Mockito 是一个简单的流行的 Mock 框架。它能够帮我们创建 Mock 对象,保持单元测试的独立性。

2.1 快速入门

  • 引入依赖
<dependency>
  <groupId>org.mockito</groupId>
  <artifactId>mockito-core</artifactId>
  <version>3.6.28</version>
</dependency>
  • 创建 Mock 对象并注入

通过方法创建手动注入

class CreateMock {
  @Before
  public void setup() {
    mockUserDao = mock(UserDao.class);  
    userService = new UserServiceImpl();  
    userService.setUserDao(mockUserDao);  
  }
}

通过注解创建并自动注入

class CreateMock {
  @Mock
  UserDao mockUserDao;
  @InjectMocks  
  private UserServiceImpl userService;  
  @Before  
  public void setUp() {  
    //初始化对象的注解 MockitoAnnotations.initMocks(this); 
  }  
}
  • 基本使用
import org.junit.Assert;
import org.junit.Test;
import java.util.List;import static org.mockito.Mockito.*;
public class MyTest {
    @Test
    public void myTest() {
        /* 创建 Mock 对象 */
        List list = mock(List.class);
        /* 设置预期,当调用 get(0) 方法时返回 "111" */
        when(list.get(0)).thenReturn("111");
        Assert.assertEquals("asd", 1, 1);
        /* 设置后返回期望的结果 */
        System.out.println(list.get(0));
        /* 没有设置则返回 null */
        System.out.println(list.get(1));
        /* 对 Mock 对象设置无效 */
        list.add("12");
        list.add("123");
        /* 返回之前设置的结果 */
        System.out.println(list.get(0));
        /* 返回 null */
        System.out.println(list.get(1));
        /* size 大小为 0 */
        System.out.println(list.size());
        /* 验证操作,验证 get(0) 调用了 2 次 */
        verify(list, times(2)).get(0);
        /* 验证返回结果 */
        String ret = (String)list.get(0);
        Assert.assertEquals(ret, "111");
    }
}  

2.2 基础语法

Mockito 的底层原理是使用 cglib 动态生成一个 代理类对象,因此,mock 出来的对象其实质就是一个 代理,该代理在 没有配置/指定行为 的情况下,默认返回空值

2.2.1 生成mock对象

  • 方式1:直接调用mock静态方法
List mockList = mock(List.class);
  • 方式2:使用@Mock等注解
@Mock
private List mockList;
@BeforeEach
	public void setUp(){
    MockitoAnnotations.openMocks(this);
  }    
  @Test
	@Order(2)
	public void testMockAnnotationField(){
		Assertions.assertNotNull(mockList);
  }  

其中MockitoAnnotations.openMocks(this)会生成@Mock、@Spy备注的mock对象。

还有对@InjectMocks标注的对象,按类型注入已经生成好的mock对象(注入到成员变量,根据field、setter或构造方法注入)

@Mock
private HelloDao mockHelloDao;
@InjectMocks
private HelloService helloService;

@BeforeEach
public void setUp(){
		MockitoAnnotations.openMocks(this);
}

@Test
@Order(3)
public void testGenerateAndInjectMock(){
		Assertions.assertNotNull(mockHelloDao);
}

public class HelloService {
	private HelloDao helloDao;
  	public HelloService(HelloDao helloDao){
		this.helloDao = helloDao;
	}
}  
  • 生成Spy对象

首先会对真实实例进行复制到spy实例,所有的方法调用都会调用到spy实例不会发生在真实实例上。

spy对象除了设置预期行为的方法外,其他方法调用会和原对象的行为一致,达到部分mock的效果。

  @Test
	public void spyBasedObject(){
		List<Integer> realList = new ArrayList<>();
		List spyList = spy(realList);
		//此时when里的spyList.add(3)不会被预期拦截
		when(spyList.add(3)).thenReturn(true);
		spyList.add(2);
		//会被预期拦截,虽然返回true
		boolean addResult1 = spyList.add(3);
		System.out.println("addResult:"+addResult1);
		//会被预期拦截,虽然返回true
		boolean addResult2 = spyList.add(3);
		System.out.println("addResult:"+addResult2);
		System.out.println("spyList:"+ JSON.toJSONString(spyList));
		System.out.println("realList:"+ JSON.toJSONString(realList));
		
		spyList.clear();
		System.out.println("spyList:"+ JSON.toJSONString(spyList));
		//使用这种语法此时when里的spyList.add(3)可以被预期拦截
		doReturn(true).when(spyList).add(3);
		System.out.println(JSON.toJSONString(spyList));

		spyList.clear();
		doCallRealMethod().when(spyList).add(3);
		spyList.add(3);
		System.out.println("spyList:"+ JSON.toJSONString(spyList));
		System.out.println("realList:"+ JSON.toJSONString(realList));

		spyList.clear();
		when(spyList.size()).thenCallRealMethod();
		System.out.println("spyList:"+ JSON.toJSONString(spyList));
		System.out.println("realList:"+ JSON.toJSONString(realList));
	}

需注意的是:

通过when和andThen的方式设置预期时,when里的调用会真实发生不会用预期拦截。

要避免when里的真实调用,可以使用doReturn这种语法。


  • mock对象当作Spy对象使用
  /**
	 * 1.默认mock所有方法不会真实调用mock对象
	 *   但可以通过thenCallRealMethod和doCallRealMethod来指定哪些方法真实调用
	 * 2.达到和spy一样局部mock的能力
	 */
	@Test
	@Order(4)
	public void useAsSpy(){
		HelloDao helloDao = mock(HelloDao.class);
		//指定真实调用
		when(helloDao.queryId(anyLong())).thenCallRealMethod();
		helloDao.deleteAll();
		helloDao.queryId(1L);
		//指定真实调用
		doCallRealMethod().when(helloDao).insert(anyString());
		helloDao.insert("abc");
	}

2.2.2 设置预期

预期时必须符合指定方法+指定参数调用,才能返回预期的值

  • 设置单方法的预期
	@Test
	public void expectReturnSingleCall(){
		List mockList = mock(List.class);
		when(mockList.get(0)).thenReturn("000");
		when(mockList.get(0)).thenReturn("111");
		//如果没有命中设置的预期,调用方法不会有任何行为。return对应方法返回值类型的默认值
		mockList.add(1);
		mockList.add(2);
		//只会使用设置的预期返回值
		Assertions.assertEquals(mockList.get(0),"111");
		//返回多次都生效
		Assertions.assertEquals(mockList.get(0),"111");
		//未设置预期返回值的return返回类型的默认值
		Assertions.assertNull(mockList.get(1));
	}

  • 设置预期调用时序

设置预期时可以使用thenReturn和thenThrow交替使用

  @Test
	@Order(2)
	public void expectReturnSequenceCall1(){
		List mockList = mock(List.class);
		//代码形式1
		when(mockList.get(0)).thenReturn("111").thenReturn("222");
		Assertions.assertEquals(mockList.get(0),"111");
		Assertions.assertEquals(mockList.get(0),"222");
		Assertions.assertEquals(mockList.get(0),"222");
	}

  /**
	 * 代码形式2: 意义和上面是一样的
	 */
	@Test
	@Order(2)
	public void expectReturnSequenceCall2(){
		List mockList = mock(List.class);
		//代码形式2
		when(mockList.get(0)).thenReturn("111","222");
		Assertions.assertEquals(mockList.get(0),"111");
		Assertions.assertEquals(mockList.get(0),"222");
		Assertions.assertEquals(mockList.get(0),"222");
	}

  /**
	 * 代码形式3: 意义和上面是一样的
	 */
	@Test
	@Order(2)
	public void expectReturnSequenceCall3(){
		List mockList = mock(List.class);
		//代码形式3
		doReturn("111").doReturn("222").when(mockList).get(0);
		Assertions.assertEquals(mockList.get(0),"111");
		Assertions.assertEquals(mockList.get(0),"222");
		Assertions.assertEquals(mockList.get(0),"222");
	}

  • 用given和will系列代替when和then系列
  /**
	 * 使用given和will*系列设置预期行为
	 */
	@Test
	@Order(5)
	public void expectReturnUsingGiven(){
		List mockList = mock(List.class);
		given(mockList.size()).willReturn(1);
		Assertions.assertEquals(1,mockList.size());
		given(mockList.size()).willThrow(new RuntimeException());
		Assertions.assertThrows(RuntimeException.class,() -> mockList.size());
	}

  • 对返回值为void的方法设置预期
    /**
	 * 对于返回值为void的方法需要设置预期
	 * 1.用doNothing的语法
	 * 2.用doAnswer的语法,也可以用现成的Answer:
	 *      Answers.RETURNS_DEFAULTS
	 *      Answers.RETURNS_SMART_NULLS
	 *      Answers.RETURNS_MOCKS
	 *      Answers.RETURNS_DEEP_STUBS
	 *      Answers.CALLS_REAL_METHODS
	 *      Answers.RETURNS_SELF
	 */
	@Test
	@Order(6)
	public void mockVoidMethod(){
		HelloDao mockHelloDao = mock(HelloDao.class);

		doAnswer(invocationOnMock -> {
			Object[] arguments = invocationOnMock.getArguments();
			System.out.println("arguments:"+ JSON.toJSONString(arguments));
			return "success";
		}).when(mockHelloDao).deleteAll();

		//doNothing只能作用于返回值为void的方法
		doNothing().when(mockHelloDao).deleteAll();

		mockHelloDao.deleteAll();
		verify(mockHelloDao).deleteAll();
	}

2.2.3 检验调用结果

verify校验mock对象的行为,verify失败会抛出对应异常。

也可以结合junit4或junit5的断言一起使用。

  • 是否调用过某方法
  /**
	 * 校验是否调用过1次某个方法(指定方法+指定参数)
	 * 1. 如果确实调用过1次正常执行
	 * 2. 如果没有调用过抛出异常WantedButNotInvoked
	 * 3. 调用超过1次也会异常TooManyActualInvocations(实际调用次数比预期多)
	 */
	@Test
	public void verifyMethodCallSingleTime(){
		List mockedList = mock(List.class);
		mockedList.add("one");
		//调用过add("one")一次,则不会抛出异常
		Executable executable = () -> verify(mockedList).add("one");
		Assertions.assertDoesNotThrow(executable);
		//没有调用过add("one"),会抛出异常
		Executable executable2 = () -> verify(mockedList).add("two");
		Assertions.assertThrows(WantedButNotInvoked.class,executable2);
		mockedList.add("one");
		//调用过add("one")两次,会抛出异常
		Executable executable3 = () -> verify(mockedList).add("one");
		Assertions.assertThrows(TooManyActualInvocations.class,executable3);
	}

  • 是否调用过某方法N次
  /**
	 * 校验是否调用过某个方法指定次数(指定方法+指定参数)
	 * 1. 如果确实调用过该指定次数正常执行
	 * 2. 如果没有调用过抛出异常WantedButNotInvoked
	 * 3. 调用过但次数不一样会异常
	 * 	  TooManyActualInvocations(实际调用次数比预期多)
	 * 	  TooFewActualInvocations(实际调用次数比预期少)
	 */
	@Test
	public void verifyMethodCallMultiTimes(){
		List mockedList = mock(List.class);
		mockedList.add("one");
		mockedList.add("one");
		//调用过add("one")两次,比预期多会抛出异常
		Executable executable1 = () -> verify(mockedList,times(1)).add("one");
		Assertions.assertThrows(TooManyActualInvocations.class,executable1);
		//调用过add("one")两次,比预期少会抛出异常
		Executable executable2 = () -> verify(mockedList,times(3)).add("one");
		Assertions.assertThrows(TooFewActualInvocations.class,executable2);
		Executable executable3 = () -> verify(mockedList,times(2)).add("one");
		Assertions.assertDoesNotThrow(executable3);
	}

  • 其他关于调用次数的校验
  /**
	 * 其他关于调用次数的校验
	 */
	@Test
	public void otherTimesVerify(){
		List mockedList = mock(List.class);
		//预期:从未调用过
		verify(mockedList,never()).add(0);
		//预期:至少调用过n次
		verify(mockedList,atLeast(1)).add(0);
		//预期:至少调用过1次,相当于mockedList,atLeast(1)
		verify(mockedList,atLeastOnce()).add(0);
		//预期:至多调用过n次
		verify(mockedList,atMost(2)).add(0);
	}

  • 校验调用时序
  /**
	 * 校验事件是否按预期的顺序发生
	 * 1.构造时,将所有的mock对象作为入参
	 * 2.再按预期顺序调用InOrder的verify方法
	 */
	@Test
	public void testInOrder(){
		List mockedList = mock(List.class);
		Set set = mock(Set.class);
		Collection col = mock(Collection.class);

		set.add(1L);
		set.add(2L);
		mockedList.add("abc");
		col.add("bcd");
		InOrder inOrder = inOrder(mockedList, set, col);

		inOrder.verify(set).add(1L);
		inOrder.verify(set).add(2L);
		inOrder.verify(mockedList).add("abc");
		inOrder.verify(col).add("bcd");
	}

  • 设置错误信息
  /**
	 * verify失败时会,异常的message通过description指定
	 */
	@Test
	public void testVerifyDescription(){
		List mockedList = mock(List.class);
		mockedList.add(1);
		verify(mockedList,description("没有调用size")).size();
	}

  • 调用记录和预期设置全部清零
     /**
	 * reset: 清除所有的调用记录和预期
	 */
	@Test
	public void testReset(){
		List<Integer> mockedList = mock(List.class);
		doReturn(100).when(mockedList).size();
		System.out.println("size1:"+mockedList.size());
		verify(mockedList,description("没有调用size1")).size();
		reset(mockedList);
		//预期清除返回默认值0,调用记录清零重新记录
		System.out.println("size2"+mockedList.size());
		verify(mockedList,description("没有调用size2")).size();
	}

2.2.4 参数匹配器

ArgumentMatchers:用来定义指定特征预的参数范围,而不用每次指定单一具体的参数值。

参数匹配器可以当作任意方法的调用:常用在mock对象直接方法调用、when、verify里的mock方法调用

如果某个方法有多个参数,只要用了参数匹配器,所有参数都需用对应的参数匹配器否则报错。

This exception may occur if matchers are combined with raw values:
//incorrect:
someMethod(anyObject(), “raw String”);
When using matchers, all arguments have to be provided by matchers.
For example:
//correct:
someMethod(anyObject(), eq(“String by matcher”));

  • 常用场景
  /*
	* 一般放在: when、mock直接调用、verify里
	*/
	@Test
	@Order(1)
	public void usingScene(){
		List mockList = mock(List.class);
		//表示任意int都返回111
		when(mockList.get(anyInt())).thenReturn("111");
		Assertions.assertEquals("111",mockList.get(0));
		Assertions.assertEquals("111",mockList.get(1));
		Assertions.assertEquals("111",mockList.get(anyInt()));
		//使用int作为参数调用了3次
		verify(mockList,times(3)).get(anyInt());
		//也可以放在任意方法
		System.out.println(anyInt());
	}

  • any系列
  /**
	 * 任意类型的值都满足
	 */
	@Test
	@Order(2)
	public void anyPattern(){
		//基本类型
		System.out.println(anyByte());
		System.out.println(anyShort());
		System.out.println(anyInt());
		System.out.println(anyLong());
		System.out.println(anyFloat());
		System.out.println(anyDouble());
		System.out.println(anyBoolean());
		System.out.println(anyString());
		System.out.println(anyChar());
		//任意类型,可以使用范型
		System.out.println((String)any());
		//任意类型
		System.out.println(any(BigDecimal.class));
		//集合
		System.out.println(anyList());
		System.out.println(anySet());
		System.out.println(anyCollection());
		System.out.println(anyMap());
	}

  • 字符串相关
  @Test
	public void strPattern(){
		//包含子串
		contains("abc");
		//满足正则的字符串
		matches("\\d+");
		startsWith("abc");
		endsWith("abc");
	}

  • 自定义参数特征
  /**
	 * 自定义参数匹配:只要实现ArgumentMatcher即可
	 * public interface ArgumentMatcher<T> {
	 *     boolean matches(T var1);
	 * }
	 */
	@Test
	public void customPattern(){
		ArgumentMatcher<Integer> intMatcher = i -> i > 0;
		intThat(intMatcher);
		byteThat(null);
		shortThat(null);
		longThat(null);
		charThat(null);
		booleanThat(null);
		floatThat(null);
		doubleThat(null);
		//任意类型,范型
		argThat(null);
	}

2.2.5 参数捕捉器

对mock对象方法调用时参数进行捕捉:ArgumentCaptor

     /**
	 * 捕捉入参类型是String的入参
	 */
	@Captor
	private ArgumentCaptor<String> captor;
	
    /**
	 * 捕捉入参类型是Integer的入参
	 */
	@Captor
	private ArgumentCaptor<Integer> captorInt1;

	/**
	 * 捕捉入参类型是Integer的入参
	 */
	@Captor
	private ArgumentCaptor<Integer> captorInt2;

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

	/**
	 * 单参数类型的方法调用
	 * 1.设置入参类型的ArgumentCaptor
	 * 2.verify时调用将capture()作为调用方法的入参来捕捉该方法调用的入参
	 * 3.通过getValue()来获取最后捕捉的参数
	 * 4.getAllValues()来获取历史捕捉的参数
	 */
	@Test
	public void testSingleParamCaptor(){
		List<String> mockList = mock(List.class);
		mockList.add("java");
		mockList.add("js");
		mockList.add("c++");
		//When verify,you can capture the arguments of the calling method
		verify(mockList,times(3)).add(captor.capture());
		System.out.println(JSON.toJSONString(captor.getAllValues()));
		System.out.println(captor.getValue());
		System.out.println(captor.getValue());
		System.out.println(captor.getValue());
	}

    /**
	 * 用同一个参数捕捉器不同的方法调用,发现:
	 * 参数记录的顺序是按verify的顺序记录的,跟实际调用顺序无关
	 */
	@Test
	public void testMultiParamUseSameCapture(){
		List<String> mockList = mock(List.class);
		mockList.add("java");
		mockList.remove("js");
		mockList.add("c++");
		//When verify,you can capture the arguments of the calling method
		verify(mockList,times(2)).add(captor.capture());
		verify(mockList).remove(captor.capture());
		System.out.println(JSON.toJSONString(captor.getAllValues()));
		System.out.println(captor.getValue());
		System.out.println(captor.getValue());
		System.out.println(captor.getValue());
	}

	/**
	 * 多参数同一次方法调用,用不同的记录器记录不同的参数:
	 * 参数记录的顺序是按verify的顺序记录的,跟实际调用顺序无关
	 */
	@Test
	public void testMultiParamUseDiffCapture(){
		List<String> mockList = mock(List.class);
		mockList.subList(1,2);
		mockList.subList(3,4);
		//When verify,you can capture the arguments of the calling method
		verify(mockList,times(2)).subList(captorInt1.capture(),captorInt2.capture());
		System.out.println(JSON.toJSONString(captorInt1.getAllValues()));
		System.out.println(JSON.toJSONString(captorInt2.getAllValues()));
		System.out.println(captorInt1.getValue());
		System.out.println(captorInt2.getValue());
	}


2.2.6 mock静态方法调用

  1. mockStatic必须引入mockito-inline包
  2. mock完成后一定要使用close关掉,让静态方法走真实逻辑,否则会影响其他入口的该静态方法调用
  /**
	 * * mock某个类的静态方法调用
	 */
	@Test
	public void testMockStatic(){
		MockedStatic<MyStaticClass> myStaticClassMockedStatic = Mockito.mockStatic(MyStaticClass.class);
		Mockito.when(MyStaticClass.getKey()).thenReturn("cba");
		Assertions.assertEquals(MyStaticClass.getKey(),"cba");
		//mock返回值或异常
		Mockito.when(MyStaticClass.getKey2()).thenThrow(new RuntimeException());
		Assertions.assertThrows(RuntimeException.class,() -> MyStaticClass.getKey2());
		//关掉static方法就会走真实逻辑
		myStaticClassMockedStatic.close();
		Assertions.assertEquals(MyStaticClass.getKey(),"abc");
		Assertions.assertEquals(MyStaticClass.getKey2(),"abd");
	}

三、集成junit

3.1 集成junit4

  1. 引入mockito-core包

  2. 加上@RunWith(MockitoJUnitRunner.class),可以自动处理@Mock,@Spy,@InjectMocks等注解

@RunWith(MockitoJUnitRunner.class)
public class Demo1_MockitoWithJunit4 {
	@Mock
	public List mockList;
	@InjectMocks
	public MyMockInject myMockInject;
	/**
	 * Mock注解注入
	 */
	@Test
	public void baseMock(){
		Assert.assertNotNull(mockList);
	}
	/**
	 * InjectMocks注解
	 */
	@Test
	public void baseInject(){
		Assert.assertNotNull(myMockInject);	
		int mockSize = myMockInject.size();
		Assert.assertEquals(0,mockSize);
		when(mockList.size()).thenReturn(2);
		int expectSize = myMockInject.size();
		myMockInject.size();
		Assert.assertEquals(2,expectSize);
	}

	public static class MyMockInject{
		private List list;
		public MyMockInject(List list){
			this.list = list;
		}
		public int size(){
			System.out.println("call size");
			return list.size();
		}
	}
}

3.2 集成junit4+spring

  1. 没有专门支持spring+junit4+mockito的集成
  2. 只能手工将mock对象注入到依赖对象中
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {AppConfig.class})
public abstract class AbstractTestCase {}

public class HelloControllerTest extends AbstractTestCase {
	/**
	 * 声明mock对象
	 */
	@Mock
	private HelloService mockHelloService;
	@Autowired
	private HelloController helloController;
	/**
	 * 生成mock对象,并手动注入到被依赖对象
	 */
	@Before
	public void setUp(){
		MockitoAnnotations.openMocks(this);
		helloController.setHelloService(mockHelloService);
	}
	@Test
	public void testHello(){
		helloController.hello();
	}
}

3.1 集成junit4+springboot

  1. springboot内置了mockito相关包
  2. 和junit4+springboot,多了可以使用的注解@MockBean,@SpyBean等
@RunWith(SpringRunner.class)
@SpringBootTest(classes = AppBootStrap.class)
public class AbstractTestCase {}

/**
 * 1。使用@MockBean注解的的对象,会生成一个Mock的bean.不会生成原来的bean
 * 2。并会将该bean注入到依赖该bean的其他bean中
 * 3。正常的bean还是会正常组装注入
 */
public class HelloControllerMockBeanTest extends AbstractTestCase {
	@Autowired
	private HelloController helloController;
	@MockBean
	private HelloService helloService;
	@Test
	public void testHello(){
		helloController.hello();
	}
}

/**
 * 1。使用@SpyBean注解的的对象,会复制生成一个一样的的bean.默认行为与原对象行为一致
 * 2。并会将该bean注入到依赖该bean的其他bean中
 * 3。正常的bean还是会正常组装注入
 */
public class HelloControllerMockSpyTest extends AbstractTestCase {

	@Autowired
	private HelloController helloController;

	@SpyBean
	private HelloService helloService;

	@Test
	public void testHello(){
		System.out.println("============test1================");
		helloController.hello();
		System.out.println("============test1================");
		System.out.println("============test2================");
		Mockito.doNothing().when(helloService).sayHello();
		helloService.sayHello();
		System.out.println("============test2================");
	}
}

3.1 集成junit5

  1. 引入依赖mockito-core,mockito-junit-jupiter
  2. 启动类加上@ExtendWith(MockitoExtension.class),会自动处理@Mock,@Spy,@InjectMocks等注解
@ExtendWith(MockitoExtension.class)
public class Demo1_MockitoWithJunit5 {
	@Mock
	public List mockList;
	@InjectMocks
	public MyMockInject myMockInject;
	/**
	 * Mock注解注入
	 */
	@Test
	public void baseMock(){
		Assertions.assertNotNull(mockList);
	}
	/**
	 * InjectMocks注解
	 */
	@Test
	public void baseInject(){
		Assertions.assertNotNull(myMockInject);
		int mockSize = myMockInject.size();
		Assertions.assertEquals(0,mockSize);
		when(mockList.size()).thenReturn(2);
		int expectSize = myMockInject.size();
		myMockInject.size();
		Assertions.assertEquals(2,expectSize);
	}

	public static class MyMockInject{
		private List list;
		public MyMockInject(List list){
			this.list = list;
		}
		public int size(){
			System.out.println("call size");
			return list.size();
		}
	}
}

3.1 集成junit5+spring

  1. juni5执行器加上@ExtendWith({SpringExtension.class, MockitoExtension.class})
  2. 会自动生成@Mock的对象,并处理@InjectMocks、@Spy等注解
  3. 但代替原始bean的动作,还是要手动去setUp
@ExtendWith({SpringExtension.class, MockitoExtension.class})
@ContextConfiguration(classes = AppConfig.class)
public class AbstractTestCase {}

public class HelloControllerOnlyJunit5Test extends AbstractTestCase {
	@Autowired
	private HelloController helloController;
	@Mock
	private HelloService mockHelloService;
	@BeforeEach
	public void setUp(){
		helloController.setHelloService(mockHelloService);
	}
	@Test
	public void testHello(){
		helloController.hello();
	}
}

3.1 集成junit5+springboot

  1. spring-boot-test-starter已经集成了mockito相关包
  2. 多了可以使用的注解@MockBean,@SpyBean
@SpringBootTest(classes = AppBootStrap.class)
public class AbstractTestCase {}

/**
 * 1。使用@MockBean注解的的对象,会生成一个Mock的bean.不会生成原来的bean
 * 2。并会将该bean注入到依赖该bean的其他bean中
 * 3。正常的bean还是会正常组装注入
 */
public class HelloControllerMockBeanTest extends AbstractTestCase {
	@Autowired
	private HelloController helloController;
	@MockBean
	private HelloService helloService;
	@Test
	public void testHello(){
		System.out.println("============only junit5================");
		helloController.hello();
		System.out.println("============only junit5================");
	}
}

/**
 * 1。使用@MockBean注解的的对象,会生成一个spy的bean行为与原类型一致.不会生成原来的bean
 * 2。并会将该bean注入到依赖该bean的其他bean中
 * 3。正常的bean还是会正常组装注入
 */
public class HelloControllerSpyBeanTest extends AbstractTestCase {
	@Autowired
	private HelloController helloController;
	@SpyBean
	private HelloService helloService;
	@Test
	public void testHello(){
		System.out.println("============only junit5================");
		helloController.hello();
		System.out.println("============only junit5================");
	}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/983875.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java 编程 7个简单的调优技巧

你的Java性能调优有救了&#xff01;分享7个简单实用的Java性能调优技巧 一、以编程方式连接字符串 在Java中有很多不同的连接字符串的选项。比如&#xff0c;可以使用简单的或、良好的旧StringBuffer或StringBuilder。 那么&#xff0c;应该选择哪种方法&#xff1f; 答案取…

CSS basics

CSS(Cascading Style Sheets&#xff0c;层叠样式表)是样式化web内容的代码。CSS基础将引导您开始所需的内容。我们将回答这样的问题:我如何把文本变成红色?我如何使内容显示在(网页)布局的某个位置?我如何用背景图片和颜色装饰我的网页? 1、What is CSS? 像HTML一样&…

Android Jetpack架构组件库:Hilt

一、开发者官网关于Hilt库使用链接如下 使用 Hilt 实现依赖项注入 Hilt版本说明 二、工程目录图 请点击下面工程名称&#xff0c;跳转到代码的仓库页面&#xff0c;将工程 下载下来 Demo Code 里有详细的注释 代码&#xff1a;LearnJetpack-hilt&#xff1a;hilt版本2.48 代…

生成订单30分钟未支付,则自动取消,该怎么实现?

今天给大家上一盘硬菜&#xff0c;并且是支付中非常重要的一个技术解决方案&#xff0c;有这块业务的同学注意自己试一把了哈&#xff01; 在开发中&#xff0c;往往会遇到一些关于延时任务的需求。例如 生成订单30分钟未支付&#xff0c;则自动取消 生成订单60秒后,给用户…

sqlserver 查询数据显示行号

查询的数据需要增加一个行号 SELECT ROW_NUMBER() OVER(ORDER BY witd_wages_area ,witd_wages_type ,witd_department_id ,witd_give_out_time) 行号,ISNULL(witd_wages_area, 0) witd_wages_area ,witd_wages_type ,witd_department_id ,ISNULL(CONVERT(VARCHAR(7), witd_gi…

《逃出大英博物馆》B站千万播放,国风文化才是主流

8月两位UP主煎饼果仔呀、夏天妹妹联合共创了一支短剧《逃出大英博物馆》&#xff0c;自预告释出以来就受到广泛关注&#xff0c;微博话题超5亿次阅读。 2023年初&#xff0c;大英博物馆被盗的消息引发全球关注&#xff0c;有网友留言&#xff0c;希望“拍一部动画片&#xff0…

PyTorch多GPU训练模型——使用单GPU或CPU进行推理的方法

文章目录 1 问题描述2 模型保存方式3 单块GPU上加载模型4 CPU上加载模型5 总结 1 问题描述 PyTorch提供了非常便捷的多GPU网络训练方法&#xff1a;DataParallel和DistributedDataParallel。在涉及到一些复杂模型时&#xff0c;基本都是采用多个GPU并行训练并保存模型。但在推…

Liunx环境安装字体(simsun为例)

一&#xff1a;下载simsun字体文件包 链接&#xff1a;https://pan.baidu.com/s/1jelox8MalDJDWTyx4Z9ghw 提取码&#xff1a;tttt二&#xff1a;把解压后的simsun.ttf、simsun.ttc放到 /usr/share/fonts目录 三&#xff1a;安装 // 刷新字体缓存 [rootxxxxxx fonts]# fc-ca…

为什么大家会觉得考PMP没用?

一是在于PMP这套知识体系&#xff0c;是一套底层的项目管理逻辑框架&#xff0c;整体是比较抽象的。大家在学习工作之后&#xff0c;会有人告诉你很多职场的一些做事的规则&#xff0c;比如说对于沟通&#xff0c;有人就会告诉如何跟客户沟通跟同事相处等等&#xff0c;这其实就…

ebay运营思路|学会这些技巧,新店铺销量翻倍

Ebay是一个老牌的跨境电商&#xff0c;目前仍然是稳坐全球前列的平台&#xff0c;也是强手如云的地方&#xff0c;虽然相对于亚马逊他显得没有那么“卷”。 要在这片市场中抢占一番天地&#xff0c;首先一定要学会一些高效的运营技巧&#xff0c;今天就来分享一些Ebay运营技巧…

SVPWM的原理及法则推导和控制算法详解

空间电压矢量调制 SVPWM 技术 SVPWM是近年发展的一种比较新颖的控制方法&#xff0c;是由三相功率逆变器的六个功率开关元件组成的特定开关模式产生的脉宽调制波&#xff0c;能够使输出电流波形尽 可能接近于理想的正弦波形。空间电压矢量PWM与传统的正弦PWM不同&#xff0c;它…

chrome 谷歌浏览器 导出插件拓展和导入插件拓展

给同事部署 微软 RPA时&#xff0c;需要用到对应的chrome浏览器插件&#xff1b;谷歌浏览器没有外网是不能直接下载拓展弄了半小时后才弄好&#xff0c;竟发现没有现成的教程&#xff0c;遂补充&#xff1b; 如何打包导出 谷歌浏览器 地址栏敲 chrome://extensions/在对应的地…

如何配置远程访问以在外部网络中使用公司内部的OA办公系统——“cpolar内网穿透”

文章目录 前言1. 确认在内网下能够使用IP端口号登录OA办公系统2. 安装cpolar内网穿透3. 创建隧道映射内网OA系统服务端口4. 实现外网访问公司内网OA系统总结 前言 现在大部分公司都会在公司内网搭建使用自己的办公管理系统&#xff0c;如OA、ERP、金蝶等&#xff0c;员工只需要…

Instagram Shop如何开通?如何销售?最全面攻略

借助 Instagram 商店&#xff0c;品牌可以策划一系列可购物的商品&#xff0c;这些商品可通过其 Instagram 个人资料直接访问。这使得在应用程序上销售更容易&#xff0c;也被潜在客户发现。 一、什么是Instagram Shop&#xff1f; Instagram 商店为商家提供了一种在 Instagra…

3种等待方式,让你学会Selenium设置自动化等待测试脚本!

一、Selenium脚本为什么要设置等待方式&#xff1f;——即他的应用背景到底是什么 应用Selenium时&#xff0c;浏览器加载过程中无法立即显示对应的页面元素从而无法进行元素操作&#xff0c;需设置一定的等待时间去等待元素的出现。&#xff08;简单来说&#xff0c;就是设置…

组件以及组件间的通讯

组件 & 组件通讯 :::warning 注意 阅读本文章之前&#xff0c;你应该先要了解 ESM 模块化的 import export&#xff0c;如需要请查看 ESM 模块化。 ::: 上一篇有介绍到什么是组件化&#xff0c;就是把一个页面拆分成若干个小模块&#xff0c;然后重新组成一个页面。其中的…

iPhone 15有始终显示功能吗?它会出现在更多的苹果手机上吗?

和我们一样&#xff0c;你可能也在犹豫&#xff0c;iPhone 15将增加一个“始终显示”的功能&#xff0c;与一年前苹果Pro版手机的功能相匹配。然而&#xff0c;随着苹果9月活动的临近&#xff0c;没有太多传言可以让我们相信我们会如愿以偿。 你可能还记得&#xff0c;去年iPh…

导出Excel的技术分享-综合篇

导出Excel的技术分享-综合篇 简单的EasyExcel使用 /*** 最简单的写*/public void simpleWrite() {// 注意 simpleWrite在数据量不大的情况下可以使用&#xff08;5000以内&#xff0c;具体也要看实际情况&#xff09;&#xff0c;数据量大参照 重复多次写入// 写法1 JDK8// s…

GMSL技术让汽车数据传输更为高效(转)

目前&#xff0c;大部分车企都在其旗舰车型上配备了达到Level 2水平的自动驾驶技术&#xff0c;也就是高级自动驾驶辅助 ADAS系统。ADAS系统硬件主要由以下几部分组成&#xff0c;包括传感器、串行器、解串器、ADAS处理器等。 除了ADAS系统&#xff0c;包括传感器融合、音视频影…

Python实现SSA智能麻雀搜索算法优化LightGBM回归模型(LGBMRegressor算法)项目实战

说明&#xff1a;这是一个机器学习实战项目&#xff08;附带数据代码文档视频讲解&#xff09;&#xff0c;如需数据代码文档视频讲解可以直接到文章最后获取。 1.项目背景 麻雀搜索算法(Sparrow Search Algorithm, SSA)是一种新型的群智能优化算法&#xff0c;在2020年提出&a…