【问题标题】:How to get more than 0% coverage on sonarqube with service test如何通过服务测试获得超过 0% 的声纳覆盖率
【发布时间】:2021-07-25 23:02:21
【问题描述】:

所以我是第一次使用 Sonarqube,我真的不知道如何为我的服务类编写一个好的单元测试,其中 sonarqube 的覆盖率不是 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% 的覆盖率,我认为这是因为我没有使用服务 partyLeaderService 类,但我似乎无法找到它应该如何完成。有人可以帮助我进行 1 次测试,然后我可以自己解决剩下的问题。 提前致谢!

我的 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()
}

【问题讨论】:

    标签: spring-boot unit-testing gradle sonarqube spring-boot-test


    【解决方案1】:

    您编写了一个测试来验证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(您在编写/维护测试方面付出了多少努力与它给您的信心水平,例如,通过集成测试,您可以测试事务边界是否正常工作;但是,您需要启动应用程序上下文,确保所有其他组件处于正确状态,维护初始数据库脚本等)
    • 期望的测试范围(单元测试只测试一个组件,而所有其他依赖项都被模拟,以便它们的行为可预测;另一方面,如果ModelMapper 中的任何一个在某些情况下,示例集成测试也可能会失败或PartyLeaderRepository 坏了)

    一个常见的经验法则是为一个复杂逻辑组件编写多个单元测试,测试所有可能的路径,以及一两个集成测试(例如一个满意的路径和一个替代路径),以验证在连接时一切正常组件在一起。

    【讨论】:

    • 感谢您的代码。我有一个问题。在您编写的这行代码中: when(partyLeaderRepository.findById(3L)).thenReturn(leader);你返回领导者,但这不是在任何地方设置的。领导是什么意思?
    • 现在我收到这个错误:PartyLeaderServiceMockTest.java:51: 错误:不兼容的类型:ArgumentMatcher 不是功能接口 verify(partyLeaderRepository).save(argThat(entity ->
    • 我也收到了这个我似乎无法修复的错误:java.lang.NoSuchMethodError: 'java.lang.AutoCloseable org.mockito.MockitoAnnotations.openMocks(java.lang.Object)' 我添加了我的帖子中的 build.gradle 文件:
    • 这是一个完全不相关的问题。请提出一个单独的问题。
    • 我做了,但目前没有反应
    猜你喜欢
    • 2013-10-14
    • 2020-01-13
    • 2015-05-18
    • 1970-01-01
    • 2016-11-10
    • 2014-05-11
    • 2019-01-13
    • 1970-01-01
    • 2016-10-19
    相关资源
    最近更新 更多