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 ApplicationContext
da 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. ResourceDatabasePopulator
da 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:
@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
}
@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 ScriptUtils
ga SQL-scriptlarni tahlil qilish va bajarish vakolatlarini delegatsiya qiladi. Xuddi shunday, executeSqlScript(..)
metodlari AbstractTransactionalJUnit4SpringContextTests
va AbstractTransactionalTestNGSpringContextTests
ichki ResourceDatabasePopulator
ni 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.
@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:
@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
}
}
@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 vacom.example.MyTest
klassida aniqlangan bo'lsa, mos keluvchi sukut bo'yicha scriptclasspath: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:
@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
}
// 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.
@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
}
@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:
@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
}
@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.ExecutionPhase
dan 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 @Sql
da 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 DEFAULT
dan farqli bir qiymat berish orqali. Global @SqlConfig
annotatsiyasining atributlari har doim meros qilib olinadi, agar lokal @SqlConfig
annotatsiyasi atributlari ""
, {}
yoki DEFAULT
dan 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 ApplicationContext
da bo'lishi kerak.
Agar SqlScriptsTestExecutionListener
ning DataSource
va PlatformTransactionManager
ni 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 SqlScriptsTestExecutionListener
ning javadocida batafsil ma'lumotlar mavjud, va quyidagi misolda JUnit Jupiter bilan sodir bo'layotgan tipik test ssenariyasini ko'rsatadi:
@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.");
}
}
@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.
GO TO FULL VERSION