单元测试-更新项目
利用MeterSphere更新项目的方法来介绍
1)如何对void方法进行测试
2)如何捕获写库入参并验证
3)继续使用Mockito-inline来mock静态方法
以下是被测对象updateProject(Project project),以及经过测试之后的代码覆盖情况。
这个方法首先检查了待更新的测试项目是否在当前workspace下存在重名,如果没有重名的话,则通过projectMapper对该测试项目进行写库更新其信息。
我们编写两个用例
1)存在重名,方法抛出异常
2)检查通过,项目更新成功
存在重名,方法抛出异常
首先来看一下第一个用例
- @Test public void updateProjectServiceNameShouldNotDuplicate(){ String expected ="project_name_already_exists"; Project project= new Project(); project.setName("name"); project.setId("id"); List<Project> projects= new ArrayList<>(); projects.add(project); Mockito.when(projectMapper.selectByExample(Mockito.any(ProjectExample.class))).thenReturn(projects); //数据库中已存在记录条数为1 try ( MockedStatic<Translator> translator= Mockito.mockStatic(Translator.class); MockedStatic<SessionUtils> sessionUtils= Mockito.mockStatic(SessionUtils.class); ){ sessionUtils.when(() -> { SessionUtils.getCurrentWorkspaceId();}).thenReturn("id"); translator.when(() -> Translator.get("project_name_already_exists")).thenReturn(expected); assertThatThrownBy(() -> projectService.updateProject(project)).hasMessage(expected); } }
这里使用的是之前关于测试计划的单元测试中已经使用过的测试工具Mockito-inline来mockSessionUtils.getCurrentWorkspaceId()和Translator.get("project_name_already_exists")这两个静态方法,形成有效的测试桩让测试用例能顺利覆盖测试点。
检查通过,项目更新成功
接下来,来看下如何完成测试项目更新的测试用例
代码语言:javascript复制 package io.metersphere.service;
import io.metersphere.base.domain.Project;
import io.metersphere.base.domain.ProjectExample;
import io.metersphere.base.mapper.ProjectMapper;
import io.metersphere.commons.utils.SessionUtils;
import io.metersphere.i18n.Translator;
import net.javacrumbs.jsonunit.core.Option;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.*;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import java.util.ArrayList;
import java.util.List;
import static net.javacrumbs.jsonunit.assertj.JsonAssertions.assertThatJson;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.Mockito.verify;
@ExtendWith(SpringExtension.class)
@ExtendWith(MockitoExtension.class)
public class ProjectServiceUpdateProjectTest {
@Mock
private ProjectMapper projectMapper;
@InjectMocks
ProjectService projectService;
@Captor
ArgumentCaptor<Project> projectArgumentCaptor;
@Test
public void updateProjectSuccess(){
Project project= new Project();
project.setName("name");
project.setId("id");
List<Project> projects= new ArrayList<>();
Mockito.when(projectMapper.selectByExample(Mockito.any(ProjectExample.class))).thenReturn(projects);
//利用Mockito-inline来mock静态方法
// 数据库中已存在记录条数为0
try ( MockedStatic<SessionUtils> sessionUtils= Mockito.mockStatic(SessionUtils.class);
){
sessionUtils.when(() -> { SessionUtils.getCurrentWorkspaceId();}).thenReturn("id");
//调用被测方法,请注意返回值是void类型
projectService.updateProject(project);
//验证写库并获取写库的入参进行进一步验证
verify(projectMapper).updateByPrimaryKeySelective(projectArgumentCaptor.capture());
Project projectCapture = projectArgumentCaptor.getValue();
//断言更新时间非空,并且更新内容是入参
assertThat(projectCapture.getUpdateTime()).isNotNull();
assertThatJson(project).when(Option.IGNORING_EXTRA_FIELDS).isEqualTo(projectCapture);
}
}
}
由于updateProject是一个返回值为void的方法,如何来验证测试项目更新成功呢?笔者采用了以下的验证点
1)Project写库,即projectMapper.updateByPrimaryKeySelective(project)方法被调用一次
2)写库内容符合预期,如id/name是入参提供的,更新时间非空
这里,我们使用了Mockito的verify来验证mapper方法是否被调用。用ArgumentCaptor来获取mapper方法的入参,并进行验证。
当然,从代码健壮性的角度来看,也建议MeterSphere对Project入参提供一下统一的检测方法,如project非空、name非空等等。