带有@nested junit课程的春季测试@transactional

发布于 2025-02-03 02:26:24 字数 3905 浏览 3 评论 0 原文

我正在春季交易中遇到问题:即使我在输出中看到每种测试方法后都会创建并滚动交易;当我检查数据库内容时,它仍然可以保留在交易期间保存的文档。 我在此处以副本模式运行mongoDB实例,以按照说明从此处

我的测试类定义如下:

@Transactional
@AutoConfigureMockMvc
@ActiveProfiles(profiles = ["test"])
@DisplayName("Login Functionality Test")
@SpringBootTest(classes = [TestConfiguration::class])
class LoginFunctionalityTest @Autowired constructor(
    private val mockMvc: MockMvc,
    private val userRepository: UserRepository,
    private val openUserRepository: OpenUserRepository,
    private val patientRepository: PatientRepository,
    private val passwordEncoder: PasswordEncoder,
    private val jwtMatcher: JWTMatcher,
    @Value("\${secret:sD1fRUWtBdfA8BNcbf}") private val fastLoginSecret: String
) {

    private val existingUsersPassword = "SOME_PASSWORD"
    private val userFastLoginTokenSecret = "ANY_SECRET"

    private lateinit var existingUser: User
    private lateinit var existingOpenUser: OpenUser
    private lateinit var existingPatient: Patient

    @BeforeEach
    fun prepareContext() {
        println("Init db")
        existingUser = userRepository.save(User(null, now(), "test", "test", "[email protected]", passwordEncoder.encode(existingUsersPassword), UserAuthority.Patient, true, true))
        existingOpenUser = openUserRepository.save(OpenUser(null, "ANY", nextExpiryDate()))
        existingPatient = patientRepository.save(Patient(null, existingUser))
    }

    @DisplayName("Login Controller")
    @Nested
    inner class LoginControllerTest{

        @Test
        fun `should return unauthorized 401 status code when user logins with not existing email`() {
            val invalidEmail = "INVALID_EMAIL"
            assertThrows<EmptyResultDataAccessException> { userRepository.findByEmail(invalidEmail) }

            mockMvc.post("/auth/login") {
                param("username", invalidEmail)
                param("password", existingUsersPassword)
            }.andExpect {
                jsonPath("$.status", equalToIgnoringCase(HttpStatus.UNAUTHORIZED.name))
                jsonPath("$.error",StringContains(true,"Invalid login credentials"))
                jsonPath("$.data", nullValue())
                status { isUnauthorized() }
            }
        }
        ...

    }

    @ActiveProfiles(profiles = ["open-user"])
    @DisplayName("Open User Login Controller")
    @Nested
    inner class OpenUserControllerLoginTest(){

        @Test
        fun `should return bad request 400 status when any of the required login parameters are missing`(){
            val validFastLoginToken = String(Base64.getEncoder().encode(passwordEncoder.encode("$userFastLoginTokenSecret${existingUser.passwordHash}$fastLoginSecret").toByteArray()))
            mockMvc
                .post("/auth/login/fast") {
                    param("userId", existingUser.id!!)
                    param("secret", userFastLoginTokenSecret)
                    param("fastLoginToken", validFastLoginToken)
                }.andExpect {
                    jsonPath("$.data.isUserActivated", equalTo(existingUser.activated))
                    jsonPath("$.data.accessToken",jwtMatcher.matches(existingUser))
                    jsonPath("$.status", equalToIgnoringCase(HttpStatus.OK.name))
                    jsonPath("$.error", nullValue())
                    status { isOk() }
                    content { contentType(MediaType.APPLICATION_JSON) }
                }
        }
        ...

    }

控制台中的输出具有在交易的创建和卷后打印的“ init db”。

仅当我将@ActiveProfiles从@nested类移至外部类时,它才能正常工作。似乎@ActiveProfiles会导致上下文重新加载,但我不知道为什么这会导致交易问题。

I am encountering a problem in spring transactions: even though I see in the output that a transaction is created and rolled back after each test method; when I check the database content, it still keeps the document that was saved during the transaction.
I ran mongodb instance in replica mode following instructions from here https://www.mongodb.com/docs/manual/tutorial/deploy-replica-set-for-testing/.

My test class is defined as follows:

@Transactional
@AutoConfigureMockMvc
@ActiveProfiles(profiles = ["test"])
@DisplayName("Login Functionality Test")
@SpringBootTest(classes = [TestConfiguration::class])
class LoginFunctionalityTest @Autowired constructor(
    private val mockMvc: MockMvc,
    private val userRepository: UserRepository,
    private val openUserRepository: OpenUserRepository,
    private val patientRepository: PatientRepository,
    private val passwordEncoder: PasswordEncoder,
    private val jwtMatcher: JWTMatcher,
    @Value("\${secret:sD1fRUWtBdfA8BNcbf}") private val fastLoginSecret: String
) {

    private val existingUsersPassword = "SOME_PASSWORD"
    private val userFastLoginTokenSecret = "ANY_SECRET"

    private lateinit var existingUser: User
    private lateinit var existingOpenUser: OpenUser
    private lateinit var existingPatient: Patient

    @BeforeEach
    fun prepareContext() {
        println("Init db")
        existingUser = userRepository.save(User(null, now(), "test", "test", "[email protected]", passwordEncoder.encode(existingUsersPassword), UserAuthority.Patient, true, true))
        existingOpenUser = openUserRepository.save(OpenUser(null, "ANY", nextExpiryDate()))
        existingPatient = patientRepository.save(Patient(null, existingUser))
    }

    @DisplayName("Login Controller")
    @Nested
    inner class LoginControllerTest{

        @Test
        fun `should return unauthorized 401 status code when user logins with not existing email`() {
            val invalidEmail = "INVALID_EMAIL"
            assertThrows<EmptyResultDataAccessException> { userRepository.findByEmail(invalidEmail) }

            mockMvc.post("/auth/login") {
                param("username", invalidEmail)
                param("password", existingUsersPassword)
            }.andExpect {
                jsonPath("$.status", equalToIgnoringCase(HttpStatus.UNAUTHORIZED.name))
                jsonPath("$.error",StringContains(true,"Invalid login credentials"))
                jsonPath("$.data", nullValue())
                status { isUnauthorized() }
            }
        }
        ...

    }

    @ActiveProfiles(profiles = ["open-user"])
    @DisplayName("Open User Login Controller")
    @Nested
    inner class OpenUserControllerLoginTest(){

        @Test
        fun `should return bad request 400 status when any of the required login parameters are missing`(){
            val validFastLoginToken = String(Base64.getEncoder().encode(passwordEncoder.encode("$userFastLoginTokenSecret${existingUser.passwordHash}$fastLoginSecret").toByteArray()))
            mockMvc
                .post("/auth/login/fast") {
                    param("userId", existingUser.id!!)
                    param("secret", userFastLoginTokenSecret)
                    param("fastLoginToken", validFastLoginToken)
                }.andExpect {
                    jsonPath("$.data.isUserActivated", equalTo(existingUser.activated))
                    jsonPath("$.data.accessToken",jwtMatcher.matches(existingUser))
                    jsonPath("$.status", equalToIgnoringCase(HttpStatus.OK.name))
                    jsonPath("$.error", nullValue())
                    status { isOk() }
                    content { contentType(MediaType.APPLICATION_JSON) }
                }
        }
        ...

    }

The output in console has the "Init db" printed between creation and roll back of transaction.

It works correctly only if I move @ActiveProfiles from @Nested class to the outer class. Seems like @ActiveProfiles causes context reload but I don't know why this causes problems with transactions.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文