Mockito编写Service层单元测试

上一篇记录了针对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
  • 4
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
当涉及到Service单元测试时,考虑使用Mockito框架(一个基于Mock技术的Java测试框架)。以下是一个基本的Service单元测试流程: 1. 创建一个Service类和相应的Dao类。 2. 创建一个Service测试类,并在其中实例化Service类和Dao类。 3. 在测试类中模拟Dao类的方法,以便在测试期间将返回值假定为预期的结果。 4. 编写测试用例,使用Mockito框架mock掉Dao类的返回值,并使用断言来验证结果是否是预期的。 以下是一个示例: ```java public class UserServiceTest { // Create a mock instance of the UserDao interface private UserDao userDao = mock(UserDao.class); // Create an instance of UserService using the mock UserDao private UserService userService = new UserServiceImpl(userDao); @Test public void testGetAllUsers() { // Mock the behavior of the UserDao's getAllUsers method to return a predefined list of users when(userDao.getAllUsers()).thenReturn(Arrays.asList(new User("John"), new User("Bob"))); // Call the getAllUsers method of UserService List<User> users = userService.getAllUsers(); // Verify that the UserDao's getAllUsers method was called exactly once verify(userDao, times(1)).getAllUsers(); // Verify that the returned list of users contains exactly two users assertEquals(2, users.size()); // Verify that the first user's name is "John" assertEquals("John", users.get(0).getName()); // Verify that the second user's name is "Bob" assertEquals("Bob", users.get(1).getName()); } } ``` 在此示例中,我们模拟了UserDao的getAllUsers方法,并在测试UserService的getAllUsers方法时使用了模拟返回值。我们还使用断言来验证UserService返回的结果,以确保它们是我们预期的结果。最后,我们还使用verify来检查我们模拟的UserDao方法实际被调用了一次。 注意:在编写测试用例时,我们不能假设Dao类的实现是正确的,因此需要使用Mockito框架模拟Dao类的返回值。使用模拟对象确保单元测试不依赖于外部系统的状态。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值