上一篇记录了针对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