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

网友投稿 3579 2022-10-12


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

一、mock 静态方法

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

第一步:给类添加注解

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

@ContextConfiguration

@RunWith(PowerMockRunner.class)

@PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class)

@PrepareForTest(静态调用类.class)

public class SupplierServiceImplTest extends PowerMockTestCase {}

第二步:mock使用

@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());

// 静态方法mock

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

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

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

supplierServiceImpl.addSupplierAccount(supplierAccountDtovdiSBx);

verify(pwEncoder).encode(randomPWd);

}

二、mock void 方法

// void嘛,doNothing顾名思义

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

使用PowerMockito和Mockito进行模拟测试

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

一 普通spring项目

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

org.mockito

mockito-all

2.0.2-beta

test

org.powermock

powermock-api-mockito

1.7.4

test

org.powermock

powermock-module-junit4

2.0.0

test

org.powermock

powermock-core

1.7.4

test

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

这里有几个要点:

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

一 mock对象

order = mock(Order.class);

user = mock(User.class);

二 属性注入

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

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

//account 获取stub

PowerMockito.mockStatic(Account.class);

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

四 私有方法

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

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

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

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

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

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

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

所以一直不成功:

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

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

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

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

PowerMockito.doReturn("2000").when(orderService, "getKeepvdiSBxtimeByWxcidAndHotelidAndLevel",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 依赖

org.mockito

mockito-all

2.0.2-beta

test

org.powermock

powermock-api-mockito2

2.0.0-beta.5

test

org.powermock

powermock-module-junit4

2.0.0-beta.5&vdiSBxlt;/version>

test

org.powermock

powermock-core

2.0.0-RC.4

test

cglib

cglib

3.2.9

org.mockito

mockito-inline

2.15.0

org.assertj

assertj-core

3.12.2

test

org.easymock

easymock

4.0.2

test

2 创建测试基类

/**

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

*/

@PowerMockRunnerDelegate(SpringRunner.class)

@RunWith(PowerMockRunner.class)

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

@SpringBootTest

public class TestBase {

}

3 创建特定的测试类

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 模拟私有方法和静态方法

@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项目的启动类只能有一个,即需要把其他sevdiSBxrvice,dao,common模块的启动类的启动注解给注释掉,否则测试启动会报错


版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:EasyPlayer播放H.265的HLS视频流,ts加载频繁导致浏览器卡顿是什么原因?(html5播放器卡顿)
下一篇:OSPF多区域 路由重分发(ospf多区域配置命令互通)
相关文章

 发表评论

暂时没有评论,来抢沙发吧~