Mockito编写Service层单元测试

本文记录针对Service层的单元测试及踩坑要点。指出Mockito不支持static及非public方法或变量的mock,可使用PowerMockito;推荐用BaseTest并加注解。介绍依赖环境、BaseTest代码设置,还说明了测试类的注意事项,如static类注解、异常测试方式等。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上一篇记录了针对Controller层的单元测试,这一篇看一下针对Service层的测试,以及踩过的坑。
由于业务层代码跟公司实际业务紧密相关,不方便贴代码,如有需要的地方会简短的写几行帮助理解,总的来说有以下几个要点:

  • Mockito框架不支持static以及非public的方法或成员变量的mock,如有需要可使用PowerMockito框架
  • 注意大多数工具类也是static的
  • 推荐使用BaseTest并加上基本的测试注解,之后的测试类继承此类即可,可以省去不少注解

先看一下依赖环境,我这里是gradle工程,包名都是一样的,去maven仓库搜就可以。

testCompile('org.springframework.boot:spring-boot-starter-test')
testCompile group: 'org.powermock', name: 'powermock-api-mockito2', version: '2.0.2'
testCompile group: 'org.powermock', name: 'powermock-module-junit4', version: '2.0.2'

powermock包本身有对mockito的依赖,所以不用重复引用mockito,上面这两个powermock的包都是必须的,缺一不可。


BaseTest.java代码如下

@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(SpringRunner.class)
@PowerMockIgnore({"javax.management.*", "javax.net.ssl.*", "com.rabbitmq.*", "org.apache.log4j.*"})
@SpringBootTest
public abstract class BaseTest {
}

设为abstract的目的是在运行单元测试的时候不运行这个类。
PowerMockIgnore注解是排除后面列出的相关类不被mock,一般来说javax.management.*javax.net.ssl.*这两个包是必须要有的。如果启动报错的话就要加上出错的包。


看一下测试类

@PrepareForTest({OSClientRequestUtil.class, ValidatorUtil.class, RestTemplateUtil.class})
public class ServiceImplTest extends BaseTest {
    @InjectMocks
    private ServiceImpl iserviceImpl;
    
    @Mock
    private Server server;

	@Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);
        PowerMockito.mockStatic(OSClientRequestUtil.class);
        PowerMockito.mockStatic(RestTemplateUtil.class);

        PowerMockito.when(OSClientRequestUtil.getOSClient(Mockito.any(), Mockito.any(), Mockito.any()))
                .thenReturn(osClientV3);
        PowerMockito.when(RestTemplateUtil.doPostForWebsocket(Mockito.anyBoolean(), Mockito.anyString(), Mockito.any()))
                .thenReturn(new JSONObject());
    }

	@Test
    public void attachVolumeTest() {
    	//对相关方法进行mock
    	Mockito.when(method).thenReturn(something);
    	......

		//断言方法返回值
		Assert.assertEquals(serviceImpl.method(parms), ReturnMsgUtil.success());
	
		//异常测试
		try {
			//异常的抛出方式与实际代码有关,可以throw一个异常,也可以返回null值
            Mockito.when(method).thenReturn(null);

            indiskServiceImpl.method(params);
            Assert.fail("异常未捕获");
        } catch (BaseException e) {
           	//对抛出的异常进行断言
           	Assert.assertEquals(exception.code, e.getCode());
        }
    }
}

做几点说明:

  • 用到的所有static类,都要在测试类类名上添加@PrepareForTest注解,以便让PowerMockito能识别他们
  • 在setUp方法中,对于所有的static类要添加PowerMockito.mockStatic()语句,否则会报空指针异常(当然把mockStatic写在测试方法里面,也是可以的)
  • 异常测试有两种方式,一种是通过Junit的@Rule注解,一种是通过try..catch然后断言的方式。@Rule方式更简洁,但如果要在一个测试方法中连续测试多个抛出的异常只能使用第二种方式,因为@Rule方式在异常抛出之后程序就终止了,无法继续进行
  • 对于无返回值方法仅需要对其进行mock就可以了,不需要特别设定返回值
  • 多次mock时务必注意先后顺序。上文的mock结果会在下一次mock时仍然生效。比如先when(method.getList()).thenReturn(null)之后,又继续写when(method.getList().get(0)).thenReturn("abc")会导致NPE
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值