好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

如何使用Mockito调用静态方法和void方法

一、mock 静态方法

mockito库并不能mock静态方法,需要依赖powermock

第一步:给类添加注解

?

1

2

3

4

5

6

// 静态类优先加载,所以需要提前告诉powermock哪些静态类需要mock

@ContextConfiguration

@RunWith (PowerMockRunner. class )

@PowerMockRunnerDelegate (SpringJUnit4ClassRunner. class )

@PrepareForTest (静态调用类. class )

public class SupplierServiceImplTest extends PowerMockTestCase {}

第二步:mock使用

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

@Test (expectedExceptions = BusinessException. class )

public void testAddSupplierAccount_genIdentityNoError() {

     // 告诉powermock,需要mock该类的所有静态方法

  PowerMockito.mockStatic(PasswordGenerator. class );

 

  final SupplierAccountDto supplierAccountDto = new SupplierAccountDto();

  supplierAccountDto.setName( "小明" );

  final String randomPWd = "666" ;

  PowerMockito.when(supplierDao.selectByEmail(anyString()))

    .thenReturn( new ArrayList<HaitaoSupplier>());

  // 静态方法mock

  PowerMockito.when(PasswordGenerator.genPwd()).thenReturn(randomPWd);

  PowerMockito.when(pwEncoder.encode(anyString())).thenReturn(randomPWd);

  PowerMockito.when(identityNoGenerator.genIdentityNo()).thenReturn(-1L);

 

  supplierServiceImpl.addSupplierAccount(supplierAccountDto);

  verify(pwEncoder).encode(randomPWd);

}

二、mock void 方法

?

1

2

// void嘛,doNothing顾名思义

PowerMockito.doNothing().when(casService).addSupplier(anyLong(), any(ServiceKey. class ));

使用PowerMockito和Mockito进行模拟测试

包括静态方法测试,私有方法测试等,以及方法执行的坑或者模拟不成功解决

一 普通spring项目

依赖:这个很重要,不同版本用法也有点区别:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

< dependency >

     < groupId >org.mockito</ groupId >

     < artifactId >mockito-all</ artifactId >

     < version >2.0.2-beta</ version >

     < scope >test</ scope >

</ dependency >

 

< dependency >

     < groupId >org.powermock</ groupId >

     < artifactId >powermock-api-mockito</ artifactId >

     < version >1.7.4</ version >

     < scope >test</ scope >

</ dependency >

< dependency >

     < groupId >org.powermock</ groupId >

     < artifactId >powermock-module-junit4</ artifactId >

     < version >2.0.0</ version >

     < scope >test</ scope >

</ dependency >

 

< dependency >

     < groupId >org.powermock</ groupId >

     < artifactId >powermock-core</ artifactId >

     < version >1.7.4</ version >

     < scope >test</ scope >

</ dependency >

接下来就是mock测试了,使用完全模拟测试过程,对于需要测试接口中调用的静态,私有方法等,返回自己想要的预期结果,达到测试效果:

这里有几个要点:

测试过程中完全手动mock,不会真实调用或者产生数据

一 mock对象

?

1

2

order = mock(Order. class );

user = mock(User. class );

二 属性注入

将service等类中需要的其他service或者mapper等mock出来,然后分别使用工具类注入,名称保持一致即可

?

1

2

3

4

5

6

7

roomTypeService = mock(RoomTypeServiceImpl. class );

ticketComponetService = mock(TicketComponetServiceImpl. class );

hotelMapper = mock(HotelMapper. class );

//注入属性

ReflectionTestUtils.setField(orderService, "hotelGroupMapper" , hotelGroupMapper);

ReflectionTestUtils.setField(orderService, "dsUtils" , dsUtils);

ReflectionTestUtils.setField(orderService, "orderMapper" , orderMapper);

三 静态方法mock

模拟静态方法返回结果需要使用PowerMockit,测试类上必须加注解@PrepareForTest

?

1

2

3

//account 获取stub

PowerMockito.mockStatic(Account. class );

Mockito.when(Account.get(anyString(), anyString(), anyString(), anyInt())).thenReturn(account);

四 私有方法

私有方法首先需要在类上加入注解,对于要测试的类中的public方法同样有效,比如测试方法中包含一个public方法,可以同样模拟:

?

1

@PrepareForTest (ConsumptionServiceImpl. class )  //里面写需要模拟私有方法的类class

然后对象不能mock,必须new一个,并且需要用spy处理:

?

1

orderService = PowerMockito.spy( new OrderServiceImpl());

接着使用doreturn .when这种形式模式,不能使用先when后return这种,会报错

注意一点,模拟参数要么全部模拟,要么全部自定义,不能混搭

这里有个大坑,如果出现私有方法还是进去执行的情况,很大可能是参数不对,比如你mock的参数是 anyString(),那么你真是测试时候传递的必须是一个String实例,不能是null,否则mock就会失败,我这里之前一直是对象的一个属性,直接new了一个对象传递

所以一直不成功:

比如 方法需要的是user.getId() ,而且你mock的是一个anyInt(),那么真正传递的时候必须给这个user,setId(9527),否则就无法达成预期的模拟效果,所有方法都一样!!

?

1

2

3

4

5

6

7

8

try {<br>         // 方法名,方法参数,必须全部对应,否则报错方法找不到

      PowerMockito.doReturn( 1 ).when(orderService, "dateListMinBook" ,anyString(),anyString(),any(RoomType. class ),anyString(),anyString());

      PowerMockito.doReturn(ResponseMessage.success().pushData( "dateRoomTypeList" , new ArrayList<DateRoomType>())).when(orderService, "eachDateNumAndPrice" ,any(Order. class ),any(RoomType. class ),anyBoolean(),anyInt(),anyString(),any(User. class ));

      PowerMockito.doReturn( "2000" ).when(orderService, "getKeeptimeByWxcidAndHotelidAndLevel" ,anyString(),anyString(),anyString());

      PowerMockito.doNothing().when(orderService, "getPayWay" ,any(),any(),any(),any(),any());

  } catch (Exception e) {

      e.printStackTrace();

  }

五 预期结果

verify :判断方法执行了几次: 确定测试是否通过

例如:verify(userService, times(1)).queryUser(any(anyInt(),anyString(),anyString());

二 springboot项目使用

1 依赖

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

<!-- S-junit -->

         < dependency >

             < groupId >org.mockito</ groupId >

             < artifactId >mockito-all</ artifactId >

             < version >2.0.2-beta</ version >

             < scope >test</ scope >

         </ dependency >

         < dependency >

             < groupId >org.powermock</ groupId >

             < artifactId >powermock-api-mockito2</ artifactId >

             < version >2.0.0-beta.5</ version >

             < scope >test</ scope >

         </ dependency >

         < dependency >

             < groupId >org.powermock</ groupId >

             < artifactId >powermock-module-junit4</ artifactId >

             < version >2.0.0-beta.5</ version >

             < scope >test</ scope >

         </ dependency >

         < dependency >

             < groupId >org.powermock</ groupId >

             < artifactId >powermock-core</ artifactId >

             < version >2.0.0-RC.4</ version >

             < scope >test</ scope >

         </ dependency >

         < dependency >

             < groupId >cglib</ groupId >

             < artifactId >cglib</ artifactId >

             < version >3.2.9</ version >

         </ dependency >

         < dependency >

             < groupId >org.mockito</ groupId >

             < artifactId >mockito-inline</ artifactId >

             < version >2.15.0</ version >

         </ dependency >

         < dependency >

             < groupId >org.assertj</ groupId >

             < artifactId >assertj-core</ artifactId >

             < version >3.12.2</ version >

             < scope >test</ scope >

         </ dependency >

         < dependency >

             < groupId >org.easymock</ groupId >

             < artifactId >easymock</ artifactId >

             < version >4.0.2</ version >

             < scope >test</ scope >

         </ dependency >

         <!-- E-junit -->

2 创建测试基类

?

1

2

3

4

5

6

7

8

9

/**

  * 测试基类,所有子测试类继承此类即可

  */

@PowerMockRunnerDelegate (SpringRunner. class )

@RunWith (PowerMockRunner. class )

@PowerMockIgnore ({ "javax.management.*" , "javax.security.*" }) //忽略一些mock异常

@SpringBootTest

public class TestBase {

}

3 创建特定的测试类

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

public class HotelControllerTest extends TestBase { //继承基类即可

     @Mock

     private HotelService hotelService;

     private Integer id;

//  加载springContext进行mock测试,真实调用方法,不需要mock步骤

//     @Autowired

//     private HotelController hotelController;

//    纯mock测试,不加载springContext,执行mock操作,必须mock步骤,不会真实调用

     @InjectMocks

     private HotelController hotelController= new HotelController();

     // 应用到所有门店测试

     @Test

     public void detailTest(){

         System.out.println( "test start....." );

         // 1 构造参数

         ininParams( 1 );

         // 2 mock步骤

         mockStep();

         // 3 执行操作

         ResponseMessage result = hotelController.detail(id);

         System.out.println( new Gson().toJson(result));

         assertEquals( 0 , ( int ) result.getCode());

     }

     private void mockStep() {

         when(hotelService.detail(anyInt())).thenReturn(ResponseMessage.success());

     }

     private void ininParams(Integer type) {

         switch (type){

             case 1 :

                 id= 17317 ;

                 break ;

             case 2 :

                 id= 2 ;

                 break ;

             default :

                 break ;

         }

     }

}

4 模拟私有方法和静态方法

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

@PrepareForTest (OrderServiceImpl. class )  // 需要调用私有或者静态方法的类

public class OrderControllerTest extends TestBase {

     private OrderServiceImpl orderServiceImpl; //需要调用私有或者静态方法时,不能使用@Mock,还需要@before初始化属性

     @Mock

     private OrderMapper orderMapper;

     @Mock

     private RestTemplateUtil restTemplateUtil;

     private Integer orderId;

     private String wxcid;

     @Before

     public void init(){

         //处理私有方法模拟实例

         orderServiceImpl = PowerMockito.spy( new OrderServiceImpl()); //使用spy模拟的需要手动注入属性,因为什么都没有

         ReflectionTestUtils.setField(orderController, "iOrderService" , orderServiceImpl);

         ReflectionTestUtils.setField(orderServiceImpl, "orderMapper" , orderMapper);

         ReflectionTestUtils.setField(orderServiceImpl, "restTemplateUtil" , restTemplateUtil);

     }

     //纯mock测试,不加载springContext,执行mock操作,必须mock步骤,不会真实调用

     @InjectMocks

     private OrderController orderController= new OrderController();

     @Test

     public void cancelTest(){

         System.out.println( "test start....." );

         // 1 构造参数

         ininParams();

         // 2 mock步骤

         mockStep();

         // 3 执行操作

         ResponseMessage cancel = orderController.cancel(wxcid, orderId);

         assertEquals( 0 ,( int )cancel.getCode());

     }

     private void mockStep() {

         Order order = new Order();

         order.setStatus( 2 );

         when(orderMapper.getOrderByOrderId(anyInt())).thenReturn(order);

         when(orderMapper.updateStatus(anyInt(),anyInt())).thenReturn( 2 );

         JsonObject jsonObject = new JsonObject();

         jsonObject.addProperty( "code" , 0 );

         when(restTemplateUtil.postToCri(anyString(),anyString(),any())).thenReturn(jsonObject);

         //处理私有方法,必须用这种写法

         try {

             PowerMockito.doNothing().when(orderServiceImpl, "returnTicketTouser" , anyString(),any());

             PowerMockito.doReturn(ErrorCode.SUCCESS).when(orderServiceImpl, "refoundAndGetCode" , any(),any(),any(),any());

         } catch (Exception e) {

             e.printStackTrace();

         }

     }

     private void ininParams() {

         wxcid= "57af462dff475fe4644de32f08406aa8" ;

         orderId= 25864 ;

     }

}

注意:

如果是分模块项目,springboot项目的启动类只能有一个,即需要把其他service,dao,common模块的启动类的启动注解给注释掉,否则测试启动会报错

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。

原文链接:https://blog.csdn.net/csdn9988680/article/details/80807736

查看更多关于如何使用Mockito调用静态方法和void方法的详细内容...

  阅读:38次