JavaRush /Kurslar /All lectures for UZ purposes /SQL-scriptlarni bajarish

SQL-scriptlarni bajarish

All lectures for UZ purposes
Daraja , Dars
Mavjud

Ma'lumotlar bazasi integratsiya testlari yozishda, ma'lumotlar bazasi sxemasini o'zgartirish yoki test ma'lumotlarini jadvallarga qo'shish uchun SQL-scriptlarni bajarish foydali bo'lishi mumkin. spring-jdbc moduli, ma'lumotlar bazasini ApplicationContextda yuklanayotganda SQL-scriptlarni bajarish orqali, kiritilgan yoki mavjud ma'lumotlar bazasini initizializatsiya qilishni qo'llab-quvvatlaydi. Batafsil ma'lumotlar uchun "Kiritilgan ma'lumotlar bazalarini qo'llab-quvvatlash" va "Kiritilgan ma'lumotlar bazasi orqali ma'lumotlarga kirishni testlash logikasi" bo'limlarni o'qib chiqing.

Garchi bir marta ApplicationContext yuklanayotganda ma'lumotlar bazasini initizializatsiya qilish juda oqilona bo'lsa-da, ba'zida integratsiya testlari davomida ma'lumotlar bazasini o'zgartirish kerak bo'ladigan holatlar bo'lishi mumkin. Quyidagi bo'limlarda, integratsiya testlari davomida SQL-scriptlarni dasturiy va deklarativ tarzda qanday ishlatishni tushuntiramiz.

Dasturiy SQL-scriptlarni bajarish

Spring, integratsiya test metodlarida dasturiy SQL-scriptlarni bajarish uchun quyidagi vositalarni taqdim etadi.

  • org.springframework.jdbc.datasource.init.ScriptUtils

  • org.springframework.jdbc.datasource.init.ResourceDatabasePopulator

  • org.springframework.test.context.junit4.AbstractTransactionalJUnit4SpringContextTests

  • org.springframework.test.context.testng.AbstractTransactionalTestNGSpringContextTests

ScriptUtils SQL-scriptlar bilan ishlash uchun statik metodlar to'plamini taqdim etadi va asosan ichki foydalanish uchun mo'ljallangan. Biroq, SQL-scriptlarni tahlil qilish va bajarishda to'liq nazorat qilish kerak bo'lsa, ScriptUtils ko'proq mos bo'lishi mumkin. Batafsil ma'lumotni javadocda ko'rishingiz mumkin.

ResourceDatabasePopulator SQL-scriptlar yordamida ma'lumotlar bazasini dasturiy to'ldirish, initizializatsiya qilish yoki tozalash uchun ob'ektga asoslangan API-interfeysini taqdim etadi. ResourceDatabasePopulator scriptlarni tahlil qilish va bajarishda ishlatiladigan belgilar kodlash, instruktsiyalar ajratgichi, sharh muhim belgilar va xatoliklar bilan ishlash bayroqlarini sozlash uchun imkoniyatlarni taqdim etadi. Har bir sozlama parametri sukut bo'yicha qiymatga ega. Javadocda batafsil ma'lumotni ko'ring. ResourceDatabasePopulatorda sozlangan scriptlarni bajarish uchun, populate(Connection) metodini chaqirib, java.sql.Connection bo'yicha yoki execute(DataSource) metodini chaqirib, javax.sql.DataSource bo'yicha bajarishingiz mumkin. Quyidagi misolda test sxemasi va test ma'lumotlari uchun SQL-scriptlar o'rnatilgan va ajratgich @@ ga o'rnatilgan, va scriptlar DataSource bo'yicha bajarilgan:

Java
@Test
void databaseTest() {
    ResourceDatabasePopulator populator = new ResourceDatabasePopulator();
    populator.addScripts(
            new ClassPathResource("test-schema.sql"),
            new ClassPathResource("test-data.sql"));
    populator.setSeparator("@@");
    populator.execute(this.dataSource);
    // test sxemasi va ma'lumotlaridan foydalanadigan kodni ishga tushiramiz
}
Kotlin
@Test
fun databaseTest() {
    val populator = ResourceDatabasePopulator()
    populator.addScripts(
            ClassPathResource("test-schema.sql"),
            ClassPathResource("test-data.sql"))
    populator.setSeparator("@@")
    populator.execute(dataSource)
    // test sxemasi va ma'lumotlaridan foydalanadigan kodni ishga tushiramiz
}

E'tibor bering, ResourceDatabasePopulator ichki ScriptUtilsga SQL-scriptlarni tahlil qilish va bajarish vakolatlarini delegatsiya qiladi. Xuddi shunday, executeSqlScript(..) metodlari AbstractTransactionalJUnit4SpringContextTests va AbstractTransactionalTestNGSpringContextTests ichki ResourceDatabasePopulatorni SQL-scriptlarni bajarishda foydalanadi. Batafsil ma'lumot executeSqlScript(..)ning turli metodlari uchun Javadocni tekshiring.

Deklarativ SQL-scriptlarni bajarish @Sql annotatsiyasi yordamida

Yuqorida aytib o'tilgan dasturiy SQL-scriptlarni bajarish mexanizmlariga qo'shimcha ravishda, SQL-scriptlarni Spring TestContext Frameworkda deklarativ tarzda sozlashingiz mumkin. Xususan, @Sql annotatsiyasini test klassi yoki test metodi uchun e'lon qilishingiz va belgilangan ma'lumotlar bazasiga oid alohida SQL-instruktsiyalar yoki SQL-scriptlar resurs yo'llarini sozlashingiz mumkin, bu integratsiya test metodi oldidan yoki undan keyin bajarilishi kerak. @Sql annotatsiyasining qo'llab-quvvatlanishi SqlScriptsTestExecutionListener tomonidan amalga oshiriladi, u sukut bo'yicha faollashtirilgan.

Metod darajasidagi @Sql annotatsiya e'lonlari sukut bo'yicha klass darajasidagi e'lonlarni uchiradi. Ammo, Spring Framework 5.2dan boshlab, bu ish rejimi har test klassi yoki har test metodi uchun @SqlMergeMode annotatsiyasi orqali sozlanishi mumkin.
Yo'l resursining semantikasi

Har bir yo'l Spring'dan Resource sifatida talqin qilinadi. Oddiy bir yo'l (masalan, "schema.sql") test klassi aniqlangan paketga nisbatan klass yo'li resursi hisoblanadi. Qiya chiziqdan boshlanuvchi yo'l (masalan, "/org/example/schema.sql") klass yo'lining mutlaq resursi bo'lib hisoblanadi. URL orqali murojaat qiluvchi yo'l (masalan, classpath:, file:, http: prefikslariga ega yo'l) berilgan resurs protokoli yordamida yuklanadi.

Quyidagi misolda JUnit Jupiterga asoslangan integratsiya test klassida klass darajasi va metod darajasida @Sql annotatsiyasini qanday ishlatishni ko'rsatadi:

Java
@SpringJUnitConfig
@Sql("/test-schema.sql")
class DatabaseTests {
    @Test
    void emptySchemaTest() {
        // hech qanday test ma'lumotlarini ishlatmagan holda test sxemasini ishlatgan kodni bajaramiz
    }
    @Test
    @Sql({"/test-schema.sql", "/test-user-data.sql"})
    void userTest() {
        // test sxemasi va test ma'lumotlarini ishlatgan kodni bajaramiz
    }
}
Kotlin
@SpringJUnitConfig
@Sql("/test-schema.sql")
class DatabaseTests {
    @Test
    fun emptySchemaTest() {
        // hech qanday test ma'lumotlarini ishlatmagan holda test sxemasini ishlatgan kodni bajaramiz
    }
    @Test
    @Sql("/test-schema.sql", "/test-user-data.sql")
    fun userTest() {
        // test sxemasi va test ma'lumotlarini ishlatgan kodni bajaramiz
    }
}
Sukut bo'yicha scriptlarni aniqlash

Agar scriptlar yoki SQL-instruktsiyalar berilmagan bo'lsa, @Sql annotatsiyasi qaerda e'lon qilinganiga qarab default scriptni aniqlashga harakat qilinadi. Agar sukut bo'yicha qiymat topilmasa, IllegalStateException istisnosi aniqlanadi.

  • Klass darajasida e'lon qilish: Agar annotatsiya qilingan test klassi - com.example.MyTest bo'lsa, unda mos keluvchi sukut bo'yicha script - classpath:com/example/MyTest.sql.

  • Metod darajasida e'lon qilish: Agar annotatsiya qilingan test metodi testMethod() nomiga ega bo'lsa va com.example.MyTest klassida aniqlangan bo'lsa, mos keluvchi sukut bo'yicha script classpath:com/example/MyTest.testMethod.sql deb nomlanadi.

Bir nechta @Sql annotatsiyalar to'plamini e'lon qilish

Agar bir xil test klassi yoki metodi uchun bir nechta SQL-scriptlar to'plamini sozlash kerak bo'lsa, ammo har bir to'plam uchun turli xil tahlil sintaksisi, xato bilan ishlash qoidalari yoki ishga tushirish fazasi bilan, bir nechta @Sql annotatsiya nusxasini e'lon qilishingiz mumkin. Java 8da @Sql annotatsiyasini takrorlanadigan annotatsiya sifatida ishlatishingiz mumkin. Yoki @SqlGroup annotatsiyasidan bir necha @Sql annotatsiya nusxalarini e'lon qilish uchun aniq konteyner sifatida foydalanishingiz mumkin.

Quyidagi misolda, Java 8da @Sql annotatsiyasini takrorlanadigan annotatsiya sifatida ishlatishni ko'rsatadi:

Java
@Test
@Sql(scripts = "/test-schema.sql", config = @SqlConfig(commentPrefix = "`"))
@Sql("/test-user-data.sql")
void userTest() {
    // test sxemasi va test ma'lumotlarini ishlatgan kodni bajaramiz
}
Kotlin
// Takrorlanadigan annotatsiyalar non-SOURCE saqlash bilan hozircha Kotlin tomonidan qo'llab-quvvatlanmaydi

Yuqoridagi misolda keltirilgan ssenariyada test-schema.sql scripti bir qatorli sharhlar uchun boshqa sintaksisdan foydalanadi.

Quyidagi misol oldingi misol bilan bir xil bo'lib, faqat @Sql annotatsiya e'lonlari @SqlGroup annotatsiyasida birlashtirilgan. Java 8 va undan yuqori versiyalarda @SqlGroup annotatsiyasini ishlatish ixtiyoriy, lekin boshqa JVM tillari, masalan, Kotlin bilan mos kelish uchun @SqlGroup annotatsiyasini ishlatishga to'g'ri kelishi mumkin.

Java
@Test
@SqlGroup({
    @Sql(scripts = "/test-schema.sql", config = @SqlConfig(commentPrefix = "`")),
    @Sql("/test-user-data.sql")
)}
void userTest() {
    // test sxemasi va test ma'lumotlarini ishlatgan kodni bajaramiz
}
Kotlin
@Test
@SqlGroup(
    Sql("/test-schema.sql", config = SqlConfig(commentPrefix = "`")),
    Sql("/test-user-data.sql"))
fun userTest() {
    // test sxemasi va test ma'lumotlarini ishlatgan kodni bajaramiz
}
Scriptlar uchun ishga tushirish fazalari

Sukut bo'yicha, SQL-scriptlar mos test metodi oldidan bajariladi. Ammo agar ba'zi scriptlar to'plamini test metodi keyin bajarish kerak bo'lsa (masalan, ma'lumotlar bazasi holatini tozalash uchun), @Sql annotatsiyasida executionPhase atributini ishlatishingiz mumkin, quyidagi misolda ko'rsatilgan:

Java
@Test
@Sql(
    scripts = "create-test-data.sql",
    config = @SqlConfig(transactionMode = ISOLATED)
)
@Sql(
    scripts = "delete-test-data.sql",
    config = @SqlConfig(transactionMode = ISOLATED),
    executionPhase = AFTER_TEST_METHOD
)
void userTest() {
    // ma'lumotlar bazasida test ma'lumotlarini saqlashni buyurtiradigan kodni bajaramiz
    // test tranzaktsiyasidan tashqarida
}
Kotlin
@Test
@SqlGroup(
    Sql("create-test-data.sql",
        config = SqlConfig(transactionMode = ISOLATED)),
    Sql("delete-test-data.sql",
        config = SqlConfig(transactionMode = ISOLATED),
        executionPhase = AFTER_TEST_METHOD))
fun userTest() {
    // ma'lumotlar bazasida test ma'lumotlarini saqlashni buyurtiradigan kodni bajaramiz
    // test tranzaktsiyasidan tashqarida
}

E'tibor bering, ISOLATED va AFTER_TEST_METHOD mos ravishda Sql.TransactionMode va Sql.ExecutionPhasedan statik import qilingan.

@SqlConfig bilan scriptni sozlash

@SqlConfig annotatsiyasi bilan scriptni tahlil qilish va xatoliklar bilan ishlashni sozlashingiz mumkin. Agar @SqlConfig annotatsiyasi integratsiya test klassiga klass darajasida e'lon qilinsa, u test klassi ierarxiyasidagi barcha SQL-scriptlar uchun global konfiguratsiya sifatida ishlaydi. @Sql annotatsiyasida to'g'ridan-to'g'ri config atributi orqali e'lon qilinganida, @SqlConfig annotatsiyasi @Sqlda e'lon qilingan SQL-scriptlar uchun lokal konfiguratsiya sifatida ishlaydi. Har bir atribut @SqlConfig annotatsiyasida default qiymatga ega, bu qiymatning javadocida dokumentatsiyalangan. Java tilining spesifikatsiyasiga ko'ra, annotation atributlariga null qiymatini qo'yish mumkin emas. Shuning uchun @SqlConfig annotatsiyasi atributlari default qiymati sifatida ya "" (satrlar uchun), {} (massivlar uchun) yoki DEFAULT (enumlar uchun) qiymatiga ega. Bu yondashuv @SqlConfig annotatsiyasining mahalliy e'lonlariga global e'lonlarni tanlab o'zgartirishga imkon beradi, "", {} yoki DEFAULTdan farqli bir qiymat berish orqali. Global @SqlConfig annotatsiyasining atributlari har doim meros qilib olinadi, agar lokal @SqlConfig annotatsiyasi atributlari "", {} yoki DEFAULTdan farqli, aniq qiymat bermasa. Shu sababli, aniq lokal konfiguratsiya global konfiguratsiyadan ustundir.

@Sql va @SqlConfig annotatsiyalari tomonidan taqdim etilgan konfiguratsiya parametrlar ScriptUtils va ResourceDatabasePopulator tomonidan qo'llab-quvvatlanadigan parametrlar bilan teng bo'lib, lekin <jdbc:initialize-database/> XML namespace elementi tomonidan taqdim etilganlardan katta. Har bir atribut uchun javadocda batafsil ma'lumotni ko'ring @Sql va @SqlConfig.

@Sql annotatsiyasi uchun tranzaktsiyalarni boshqarish

Sukut bo'yicha SqlScriptsTestExecutionListener @Sql annotatsiyasi orqali sozlangan scriptlar uchun kerakli tranzaktsion semantikasini yaratadi. Xususan, SQL-scriptlar mavjud Spring tartiblangan tranzaksiyada (masalan, TransactionalTestExecutionListener tomonidan tartiblangan tranzaktsiyada) yoki izolyatsiyalangan tranzaktsiyada berilgan ApplicationContext testida transactionMode atributining konfiguratsiyalangan qiymatiga va PlatformTransactionManager mavjudligiga ko'ra bajariladi. Ammo, eng kamida, javax.sql.DataSource testining ApplicationContextda bo'lishi kerak.

Agar SqlScriptsTestExecutionListenerning DataSource va PlatformTransactionManagerni aniqlash va tranzaktsion semantikani chiqarishni ishlatadigan algoritmlar sizning ehtiyojlaringizni qondirmasa, @SqlConfig annotatsiyasida dataSource va transactionManager atributlarini aniq nomlarini sozlashingiz mumkin. Shuningdek, @SqlConfig annotatsiyasida transactionMode atributini sozlab, tranzaktsiya tarqatish lo'gisini boshqarishingiz mumkin (masalan, scriptlarni izolyatsiyalangan tranzaktsiyada ishga tushirish kerakmi yoki yo'qmi). @Sql annotatsiyasi bilan qo'llab-quvvatlanadigan tranzaktsion boshqarish variantlarining batafsil muhokamasi ushbu manzildagi referensiyali ko'rsatmaga kiradi, @SqlConfig annotatsiyasi va SqlScriptsTestExecutionListenerning javadocida batafsil ma'lumotlar mavjud, va quyidagi misolda JUnit Jupiter bilan sodir bo'layotgan tipik test ssenariyasini ko'rsatadi:

Java
@SpringJUnitConfig(TestDatabaseConfig.class)
@Transactional
class TransactionalSqlScriptsTests {
    final JdbcTemplate jdbcTemplate;
    @Autowired
    TransactionalSqlScriptsTests(DataSource dataSource) {
        this.jdbcTemplate = new JdbcTemplate(dataSource);
    }
    @Test
    @Sql("/test-data.sql")
    void usersTest() {
        // test ma'lumotlar bazasidagi holatni tekshiramiz:
        assertNumUsers(2);
        // test ma'lumotlarini ishlatgan kodni bajaramiz...
    }
    int countRowsInTable(String tableName) {
        return JdbcTestUtils.countRowsInTable(this.jdbcTemplate, tableName);
    }
    void assertNumUsers(int expected) {
        assertEquals(expected, countRowsInTable("user"),
            "Number of rows in the [user] table.");
    }
}
Kotlin
@SpringJUnitConfig(TestDatabaseConfig::class)
@Transactional
class TransactionalSqlScriptsTests @Autowired constructor(dataSource: DataSource) {
    val jdbcTemplate: JdbcTemplate = JdbcTemplate(dataSource)
    @Test
    @Sql("/test-data.sql")
    fun usersTest() {
        // test ma'lumotlar bazasidagi holatni tekshiramiz:
        assertNumUsers(2)
        // test ma'lumotlarini ishlatgan kodni bajaramiz...
    }
    fun countRowsInTable(tableName: String): Int {
        return JdbcTestUtils.countRowsInTable(jdbcTemplate, tableName)
    }
    fun assertNumUsers(expected: Int) {
        assertEquals(expected, countRowsInTable("user"),
                "Number of rows in the [user] table.")
    }
}

E'tibor bering, usersTest() metodini bajargandan so'ng, ma'lumotlar bazasini tozalashingiz shart emas, chunki ma'lumotlar bazasiga kiritilgan har qanday o'zgartishlar (test metodidagi va /test-data.sql scripti orqali) avtomatik ravishda TransactionalTestExecutionListener tomonidan qaytariladi (batafsil tranzaktsiyalarni boshqarish bo'limida ko'rsatma qiling.).

@SqlMergeMode annotatsiyasi yordamida konfiguratsiyani birlashtirish va biriktirish

Spring Framework 5.2dan boshlab, metod darajasidagi @Sql annotatsiyalarini klass darajasidagi annotatsiyalar bilan birlashtirish mumkin. Masalan, bu test klassi uchun ma'lumotlar bazasi sxemasi yoki umumiy test ma'lumotlarini bir marta taqdim etish, so'ngra har bir test metodi uchun qo'shimcha, o'ziga xos test ma'lumotlarini taqdim etishga imkon beradi. @Sql annotatsiyalarini birlashtirishni faollashtirish uchun, test klassingiz yoki test metodiga @SqlMergeMode(MERGE) annotatsiyasini qo'shing. Aniq bir test metodi (yoki aniq bir test subklassi) uchun birlashtirishni o'chirish uchun, @SqlMergeMode(OVERRIDE) annotatsiyasi yordamida default rejimiga qaytishingiz mumkin. @SqlMergeMode annotatsiyasiga oid bo'limda misollarni ko'ring va batafsilroq ma'lumot oling.

Izohlar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION