如何通过服务测试在sonarqube上获得超过0%的覆盖率



所以我是第一次使用Sonarqube,我真的不知道如何为我的服务类编写一个好的单元测试,因为Sonarqu贝的覆盖率不是0%。

这是我想要测试的我的服务类

import com.example.demo.DTO.PartyLeaderDto;
import com.example.demo.Model.PartyLeader;
import com.example.demo.Repository.PartyLeaderRepository;
import org.modelmapper.ModelMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import javax.transaction.Transactional;
import java.util.List;
@Service
@Transactional
public class PartyLeaderService {
@Autowired
private PartyLeaderRepository partyLeaderRepository;
@Autowired
ModelMapper modelMapper;
public List<PartyLeader> listAllPartyLeaders() {
return partyLeaderRepository.findAll();
}
public void savePartyLeader(PartyLeaderDto partyLeaderDto) {
PartyLeader partyLeader = convertToEntity(partyLeaderDto);
partyLeaderRepository.save(partyLeader);
}
public PartyLeaderDto getPartyLeader(Integer id) {
PartyLeader partyLeader = partyLeaderRepository.findById(id).orElse(null);
return convertToDto(partyLeader);
}

public void deletePartyLeader(Integer id) {
partyLeaderRepository.deleteById(id);
}
public void deleteAllLeaders() {
partyLeaderRepository.deleteAll();}
private PartyLeaderDto convertToDto(PartyLeader partyLeader) {
PartyLeaderDto partyLeaderDto = modelMapper.map(partyLeader, PartyLeaderDto.class);
return partyLeaderDto;
}
private PartyLeader convertToEntity(PartyLeaderDto partyLeaderDto) {
PartyLeader entity = new PartyLeader();
entity.setId(partyLeaderDto.getId());
entity.setName(partyLeaderDto.getName());
entity.setApperance(partyLeaderDto.getApperance());
return entity;
}
}

这是我迄今为止的测试课程:

@SpringBootTest
@AutoConfigureMockMvc
public class PartyLeaderServiceTest {

@Autowired
private ModelMapper modelMapper;
@Test
public void whenConvertPartyLeaderEntityToPostDto_thenCorrect() {
PartyLeader partyLeader = new PartyLeader();
partyLeader.setId(1);
partyLeader.setName("Josse");
partyLeader.setApperance("Link of image");
PartyLeaderDto partyLeaderDto = modelMapper.map(partyLeader, PartyLeaderDto.class);
Assert.assertEquals(partyLeader.getId(), partyLeaderDto.getId());
Assert.assertEquals(partyLeader.getName(), partyLeaderDto.getName());
Assert.assertEquals(partyLeader.getApperance(), partyLeaderDto.getApperance());
}
@Test
public void whenConvertPartyDtoToPartyEntity_thenCorrect() {
PartyLeaderDto partyLeaderDto = new PartyLeaderDto();
partyLeaderDto.setId(1);
partyLeaderDto.setName("Josse");
partyLeaderDto.setApperance("Link of image");
PartyLeader partyLeader = modelMapper.map(partyLeaderDto, PartyLeader.class);
Assert.assertEquals(partyLeaderDto.getId(), partyLeader.getId());
Assert.assertEquals(partyLeaderDto.getName(), partyLeader.getName());
Assert.assertEquals(partyLeaderDto.getApperance(), partyLeader.getApperance());
}
}

这个测试提供了0%的覆盖率,我想这是因为我没有使用服务方LeaderService类,但我似乎找不到应该如何完成。有人能帮我做一个测试吗?然后我就可以自己解决剩下的问题了。提前感谢!

我的build.gradle文件

plugins {
id 'org.springframework.boot' version '2.4.2'
id 'io.spring.dependency-management' version '1.0.11.RELEASE'
id 'java'
id "org.sonarqube" version "3.0"
id 'jacoco'
}
group = 'com.example'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '15'
configurations {
compileOnly {
extendsFrom annotationProcessor
}
}
repositories {
mavenCentral()
}

dependencies {
compile 'org.apache.httpcomponents:httpcore:4.4.1'
compile 'org.apache.httpcomponents:httpclient:4.5'
implementation('io.jsonwebtoken:jjwt:0.2')
implementation 'org.springframework.boot:spring-boot-starter-mail'
implementation 'org.springframework.boot:spring-boot-starter-security'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
compile 'junit:junit:4.12'
implementation 'org.modelmapper:modelmapper:2.4.1'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'mysql:mysql-connector-java'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
implementation 'org.eclipse.jgit:org.eclipse.jgit:5.4.2.201908231537-r'
/**
* JUnit jupiter with mockito.
*/
testCompile group: 'org.mockito', name: 'mockito-junit-jupiter', version: '2.19.0'
testCompile group: 'org.mockito', name: 'mockito-core', version: '2.19.0'
testCompile group: 'org.springframework.security', name: 'spring-security-test', version: '5.1.6.RELEASE'
}
sonarqube{
properties{
property 'sonarjava.source', '1.8'
property 'sonar.java.coveragePlugin', 'jacoco'
property 'sonar.jacoco.reportPaths', 'build/reports/jacoco/test/jacocoTestReport.xml'
}
}
test {
useJUnitPlatform()
}

您已经编写了一个测试来验证ModelMapper是否正常工作。这没什么错,只是它是ModelMapperTest而不是PartyLeaderServiceTest

要测试PartyLeaderservice,您可以:

  • 编写一个单元测试,模拟所有其他依赖项

public class PartyLeaderServiceTest {
@MockitoRule
public var mockitoRule = new MockitoRule();
@Mock
private PartyLeaderRepository partyLeaderRepository;
@Mock
private ModelMapper modelMapper;
@InjectMocks
private PartyLeaderService partyLeaderService; // this is like calling new PartyLeaderService(partyLeaderRepository, modelMapper); 
@Test
void whenSavePartyLeader_thenCorrectPartyLeaderSaved() {
// given
var input = PartyLeaderDto.builder()
.name("Josse")
.appearance("Link of image")
.build();
// when
partyLeaderService.savePartyLeader(input);

// then
verify(partyLeaderRepository).savePartyLeader(argThat(entity -> 
entity.getName().equals("Josse")
&& entity.getAppearance().equals("Link of image"));
}
@Test
void whenGetPartyLeader_ShouldReturnCorrectLeaderData() {
// given
def partyLeaderEntity = PartyLeader.builder()
.name("Josse")
.appearance("Link of image")
.build();
def partyLeaderDto = PartyLeaderDto.builder()
.name("Josse")
.appearance("Link of image")
.build();
when(partyLeaderRepository.findById(3L)).thenReturn(Optional.of(partyLeaderEntity));
when(modelMapper.map(partyLeader, PartyLeaderDto.class)).thenReturn(partyLeaderDto);
// when
def result = partyLeaderService.getPartyLeader(3L);
// then
assertEqual(result, partyLeaderDto);
}
...
}
  • 编写一个集成测试,对PartyLeaderService的实际设置进行操作:
public class PartyLeaderServiceTest {
@Autowired
private PartyLeaderService partyLeaderService;
@Autowired
private EntityManager em;
@Test
void whenSavePartyLeader_thenCorrectPartyLeaderSaved() {
// given
var input = PartyLeaderDto.builder()
.name("Josse")
.appearance("Link of image")
.build();
// when
partyLeaderService.savePartyLeader(input);
def createdPartyLeader = em.createQuery("SELECT l FROM PartyLeader l", PartyLeader.class).getSingleResult();
// then
assertEqual(createdPartyLeader.getName(), "Josse");
assertEqual(createdPartyLeader.getAppearance(), "Link of image");
}
@Test
void whenGetPartyLeader_ShouldReturnCorrectLeaderData() {
// given
def partyLeaderEntity = PartyLeader.builder()
.name("Josse")
.appearance("Link of image")
.build();
entityManager.persist(partyLeaderEntity); // or use @SqlScript to insert initial data into the db
entityManager.flush();
// when
def result = partyLeaderService.getPartyLeader(partyLeaderEntity.getId());
// then
assertEqual(createdPartyLeader.getName(), "Josse");
assertEqual(createdPartyLeader.getAppearance(), "Link of image");
}
...
}
  • 创建两种方法的混合,例如,在单元测试中,您可以决定模拟partyLeaderRepository,但使用ObjectMapper的实际实现,因为模拟它太费力了

选择哪个选项主要取决于几个因素:

  • 您正在测试的组件的逻辑是否非常复杂(如果是,请使用单元测试;另一方面,如果组件只调用其他组件,尤其是第三方组件,则集成测试可能更有价值(
  • ROTI(您在编写/维护测试方面投入的精力与它给您的信心水平,例如,通过集成测试,您可以测试事务边界是否正确工作;但是,您需要调整应用程序上下文,确保所有其他组件都处于正确状态,维护初始DB脚本等(
  • 所需的测试范围(单元测试只测试一个组件,而所有其他依赖项都被模拟,以便它们的行为可以预测;另一方面,如果ModelMapperPartyLeaderRepository被破坏,示例集成测试在某些情况下也可能失败(

一个常见的经验法则是为一个复杂的逻辑组件编写几个单元测试,测试所有可能的路径,以及一到两个集成测试(例如,一个愉快的路径和一个替代路径(,以验证当您将组件连接在一起时,一切都能正常工作。

最新更新