问题描述
所以我是第一次使用 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()
}
解决方法
您编写了一个测试来验证 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(),"Link of image");
}
...
}
- 创建两种方法的混合,例如在单元测试中,您可以决定要模拟
partyLeaderRepository
,但使用ObjectMapper
的实际实现,因为模拟它太费力了。
选择哪个选项主要取决于几个因素:
- 您正在测试的组件的逻辑是否非常复杂(如果是,请使用单元测试;另一方面,如果该组件仅调用其他组件——尤其是第三方组件,则集成测试可能更有价值)
- ROTI(您在编写/维护测试方面付出了多少努力与它给您的信心水平,例如,通过集成测试,您可以测试事务边界是否正常工作;但是,您需要启动应用程序上下文,确保所有其他组件都处于正确状态,维护初始 DB 脚本等)
- 所需的测试范围(单元测试仅测试一个组件,而所有其他依赖项都被模拟,以便它们的行为可预测;另一方面,如果 {{1 }} 或
ModelMapper
坏了)
一个常见的经验法则是为一个复杂逻辑组件编写多个单元测试,测试所有可能的路径,并进行一两个集成测试(例如一个愉快的路径和一个替代路径)以验证当您连接组件在一起。