Я пытаюсь проводить модульные тесты в простом приложении CRUD на Spring boot + Kotlin. Я уже провел тесты для других объектов и репозиториев, но у меня возникли проблемы с объектом User и репозиторием. Эта таблица связана с таблицей Team, возможно поэтому стандартная логика моих тестов не работает.
Версия Springboot "3.2.4"
Сущность
@Entity
@Table(name = "\"user\"")
@DynamicUpdate
class UserEntity(
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "user_generator")
@SequenceGenerator(name = "user_generator", sequenceName = "user_id_seq", allocationSize = 1)
@Column(name = "id")
var userId: Int?,
@Column(name = "email")
val email: String,
@Enumerated(EnumType.STRING)
@Column(name = "role", columnDefinition = "user_role_enum", nullable = false)
val role: Role,
@ManyToMany(fetch = FetchType.LAZY)
@JoinTable(
name = "user_teams_team",
joinColumns = [JoinColumn(name = "user_id")],
inverseJoinColumns = [JoinColumn(name = "team_id")]
)
val teams: Set<TeamEntity>? = null
)
@Entity
@Table(name = "team")
@DynamicUpdate
class TeamEntity(
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "team_generator")
@SequenceGenerator(name = "team_generator", sequenceName = "team_id_seq", allocationSize = 1)
@Column(name = "id")
var teamId: Int?,
@Column(name = "name_ru")
val nameRu: String,
@Column(name = "name_en")
val nameEn: String,
@Column(name = "name_kk")
val nameKk: String
)
DTO
class UserDto(
val email: String,
val role: Role,
val teams: List<Int>?
)
data class UserResponseDto(
val userId: Int,
val email: String,
val role: Role,
var teams: Set<TeamEntity>?
)
Усерсервицеимпл
package kt.cell.jobsapi.service.impl
import kt.cell.jobsapi.exception.InternalServerException
import kt.cell.jobsapi.exception.NotFoundException
import kt.cell.jobsapi.model.dto.*
import kt.cell.jobsapi.model.mapper.UserMapper
import kt.cell.jobsapi.repository.UserRepository
import kt.cell.jobsapi.service.UserService
import org.springframework.dao.DataIntegrityViolationException
import org.springframework.stereotype.Service
import java.util.*
@Service
class UserServiceImpl(
val userRepository: UserRepository,
val userMapper: UserMapper,
val teamServiceImpl: TeamServiceImpl
) : UserService {
@Throws(NotFoundException::class)
override fun getUsers(): List<UserResponseDto> {
val userEntityList = userRepository.findAll()
return if (userEntityList.isNotEmpty()) {
userEntityList.map { userMapper.toDto(it) }
} else {
throw NotFoundException("No users found")
}
}
@Throws(Exception::class, DataIntegrityViolationException::class, NotFoundException::class)
override fun createUser(userDto: UserDto): UserResponseDto {
teamServiceImpl.checkIfSuchTeamsExistOrThrowNotFoundException(userDto)
val teamSet = teamServiceImpl.createTeamSetFromTeamIdsOrThrowNotFoundException(userDto)
val savedUser = userRepository.save(userMapper.toEntity(userDto, teamSet))
return userMapper.toDto(savedUser)
}
TeamServiceImpl
fun createTeamSetFromTeamIdsOrThrowNotFoundException(userDto: UserDto): MutableSet<TeamEntity> {
val teamSet: MutableSet<TeamEntity> = mutableSetOf()
userDto.teams?.forEach { teamId ->
val teamEntity = teamRepository.findById(teamId)
.orElseThrow { NotFoundException("There is no team with id: $teamId") }
teamSet.add(teamEntity)
}
return teamSet
}
fun checkIfSuchTeamsExistOrThrowNotFoundException(userDto: UserDto) {
val existingInDbTeamIdList = teamRepository.findAll().map { it.teamId!! }
userDto.teams?.forEach { teamId ->
if (teamId !in existingInDbTeamIdList) {
throw NotFoundException("There is no team with id: $teamId")
}
}
}
Усерсервицеимплтестс
@ExtendWith(SpringExtension::class)
@TestInstance(TestInstance.Lifecycle.PER_METHOD)
class UserServiceImplTests {
@Mock
private lateinit var teamMapper: TeamMapper
@Mock
private lateinit var userRepository: UserRepository
@Mock
private lateinit var teamRepository: TeamRepository
@Mock
private lateinit var teamService: TeamServiceImpl
@Mock
private lateinit var userMapper: UserMapper
@InjectMocks
private lateinit var userService: UserServiceImpl
@Captor
private lateinit var userEntityCaptor: ArgumentCaptor<UserEntity>
@Test
fun createUser_Success() {
val id = 1
val teamEntity = TeamEntity(id, "testRu", "testEn", "testKk")
val userEntity = UserEntity(id, "test", Role.OWNER, setOf(teamEntity))
val userEntity1 = UserEntity(id, "test", Role.OWNER, setOf(teamEntity))
val teamSet = mutableSetOf(teamEntity)
val userDto = UserDto("test", Role.OWNER, listOf(1))
val userResponseDto = UserResponseDto(id, "test", Role.OWNER, setOf(teamEntity))
whenever(teamRepository.findAll()).thenReturn(listOf(teamEntity))
whenever(teamRepository.findById(id)).thenReturn(Optional.of(teamEntity))
whenever(userMapper.toEntity(userDto, teamSet)).thenReturn(userEntity)
whenever(userRepository.save(userEntity)).thenReturn(userEntity)
whenever(userMapper.toDto(userEntity)).thenReturn(userResponseDto)
val result = userService.createUser(userDto)
assertEquals(userResponseDto, result)
verify(userRepository).save(userEntityCaptor.capture())
val capturedEntity = userEntityCaptor.value
assertNotNull(capturedEntity)
assertEquals(userEntity, capturedEntity)
verify(userRepository).save(userEntity)
verify(teamRepository).findAll()
}
Это сама ошибка:
save(...) must not be null
java.lang.NullPointerException: save(...) must not be null
at kt.cell.jobsapi.service.impl.UserServiceImpl.createUser(UserServiceImpl.kt:39)
at kt.cell.jobsapi.service.impl.UserServiceImplTests.createUser_Success(UserServiceImplTests.kt:123)
я просто не понимаю где искать
Кажется, я понял, что вы имеете в виду, но я не совсем понимаю, что мне нужно делать. Мой метод createTeamSetFromTeamIdsOrThrowNotFoundException
находится в пакете «teamService» (а не в userService
), так что, думаю, причина в этом. Но как мне вводить макеты? в userSerive
или в teamService
?
Пожалуйста, покажите весь UserServiceImpl
обновил код
Вы не заглушаете teamServiceImpl.createTeamSetFromTeamIdsOrThrowNotFoundException(userDto)
, поэтому он возвращает ноль. В результате аргументы, переданные в toEntity
, не совпадают, поэтому он также возвращает ноль.
спасибо за ответ, я тоже это проверю. Но теперь мой тест не доходит до похитителя, он провален раньше
Обновил ответ
вы точно получили ответ, я уже это понял. Спасибо за подсказку, которая помогла мне найти ответ!
ты забыл издеваться/заглушить
teamService
!(?;) ..или скорее ты "издевался" над этим, а не "издевался над инъекцией"...(пожалуйста, решите)