Semua pengembang basis data kurang lebih menulis pengujian unit basis data yang tidak hanya membantu mendeteksi bug lebih awal, tetapi juga menghemat banyak waktu dan upaya ketika perilaku objek basis data yang tidak diharapkan menjadi masalah produksi.
Saat ini, ada sejumlah kerangka kerja pengujian unit basis data seperti tSQLt bersama dengan alat pengujian unit pihak ketiga termasuk dbForge Unit Test.
Di satu sisi, manfaat menggunakan alat pengujian pihak ketiga adalah tim pengembangan dapat langsung membuat dan menjalankan pengujian unit dengan fitur tambahan. Selain itu, menggunakan kerangka pengujian secara langsung memberi Anda kontrol lebih besar atas pengujian unit. Oleh karena itu, Anda dapat menambahkan lebih banyak fungsionalitas ke kerangka pengujian unit itu sendiri. Namun, dalam hal ini, tim Anda harus memiliki waktu dan tingkat keahlian tertentu untuk melakukannya.
Artikel ini membahas beberapa praktik standar yang dapat membantu kami meningkatkan cara kami menulis pengujian unit basis data.
Pertama, mari kita lihat beberapa konsep kunci dari pengujian unit basis data.
Apa itu Pengujian Unit Basis Data
Menurut Dave Green, pengujian unit basis data memastikan bahwa unit kecil basis data, seperti tabel, tampilan, prosedur tersimpan, dll., berfungsi seperti yang diharapkan.
Pengujian unit basis data ditulis untuk memverifikasi apakah kode memenuhi persyaratan bisnis.
Misalnya, jika Anda menerima persyaratan seperti "Seorang pustakawan (pengguna akhir) harus dapat menambahkan buku baru ke perpustakaan (Sistem Informasi Manajemen)", Anda perlu memikirkan untuk menerapkan pengujian unit untuk prosedur tersimpan untuk memeriksa apakah itu dapat menambahkan buku baru ke Buku tabel.
Terkadang, serangkaian pengujian unit memastikan bahwa kode memenuhi persyaratan. Oleh karena itu, sebagian besar kerangka kerja pengujian unit termasuk tSQLt memungkinkan pengelompokan pengujian unit terkait ke dalam satu kelas pengujian daripada menjalankan pengujian individual.
Prinsip AAA
Perlu disebutkan tentang prinsip 3 langkah pengujian unit yang merupakan praktik standar untuk menulis pengujian unit. Prinsip AAA adalah dasar untuk pengujian unit dan terdiri dari langkah-langkah berikut:
- Mengatur/Merakit
- Bertindak
- Tegaskan
Atur bagian adalah langkah pertama dalam menulis tes unit basis data. Ini memandu melalui konfigurasi objek database untuk pengujian dan pengaturan hasil yang diharapkan.
Tindakan bagian adalah ketika objek database (sedang diuji) dipanggil untuk menghasilkan output yang sebenarnya.
Pernyataan langkah berkaitan dengan mencocokkan output aktual dengan yang diharapkan dan memverifikasi apakah tes lolos atau gagal.
Mari kita jelajahi metode ini pada contoh tertentu.
Jika kami membuat pengujian unit untuk memverifikasi bahwa AddProduct prosedur tersimpan dapat menambahkan produk baru, kami menyiapkan Produk dan Produk yang Diharapkan tabel setelah produk ditambahkan. Dalam hal ini, metode berada di bawah bagian Atur/Rakit.
Memanggil prosedur AddProduct dan memasukkan hasilnya ke dalam tabel Product dicakup oleh bagian Act.
Bagian Assert hanya mencocokkan tabel Product dengan tabel ExpectedProduct untuk melihat apakah prosedur tersimpan telah berhasil dijalankan atau gagal.
Memahami Dependensi dalam Pengujian Unit
Sejauh ini, kita telah membahas dasar-dasar pengujian unit basis data dan pentingnya prinsip AAA (Assemble, Act, and Assert) saat membuat pengujian unit standar.
Sekarang, mari kita fokus pada bagian penting lainnya dari teka-teki – ketergantungan dalam pengujian unit.
Selain mengikuti prinsip AAA dan hanya berfokus pada objek database tertentu (sedang diuji), kita juga perlu mengetahui dependensi yang dapat memengaruhi pengujian unit.
Cara terbaik untuk memahami dependensi adalah dengan melihat contoh pengujian unit.
Penyiapan Database Contoh Karyawan
Untuk melanjutkan, buat database sampel dan beri nama EmployeesSample :
-- Create the Employees sample database to demonstrate unit testing CREATE DATABASE EmployeesSample; GO
Sekarang, buat Karyawan tabel dalam database sampel:
-- Create the Employee table in the sample database USE EmployeesSample CREATE TABLE Employee (EmployeeId INT PRIMARY KEY IDENTITY(1,1), NAME VARCHAR(40), StartDate DATETIME2, Title VARCHAR(50) ); GO
Mengisi Data Sampel
Isi tabel dengan menambahkan beberapa record:
-- Adding data to the Employee table INSERT INTO Employee (NAME, StartDate, Title) VALUES ('Sam','2018-01-01', 'Developer'), ('Asif','2017-12-12','Tester'), ('Andy','2016-10-01','Senior Developer'), ('Peter','2017-11-01','Infrastructure Engineer'), ('Sadaf','2015-01-01','Business Analyst'); GO
Tabelnya terlihat seperti ini:
-- View the Employee table SELECT e.EmployeeId ,e.NAME ,e.StartDate ,e.Title FROM Employee e; GO
Harap dicatat bahwa saya menggunakan dbForge Studio untuk SQL Server dalam artikel ini. Dengan demikian, tampilan keluaran mungkin berbeda jika Anda menjalankan kode yang sama di SSMS (SQL Server Management Studio). Tidak ada perbedaan dalam hal skrip dan hasilnya.
Persyaratan Menambah Karyawan Baru
Sekarang, jika persyaratan untuk menambahkan karyawan baru telah diterima, cara terbaik untuk memenuhi persyaratan tersebut adalah dengan membuat prosedur tersimpan yang dapat berhasil menambahkan karyawan baru ke tabel.
Untuk melakukannya, buat prosedur tersimpan AddEmployee sebagai berikut:
-- Stored procedure to add a new employee CREATE PROCEDURE AddEmployee @Name VARCHAR(40), @StartDate DATETIME2, @Title VARCHAR(50) AS BEGIN SET NOCOUNT ON INSERT INTO Employee (NAME, StartDate, Title) VALUES (@Name, @StartDate, @Title); END
Uji Unit untuk Memverifikasi apakah Persyaratan Terpenuhi
Kami akan menulis pengujian unit database untuk memverifikasi apakah prosedur tersimpan AddEmployee memenuhi persyaratan untuk menambahkan catatan baru ke tabel Karyawan.
Mari kita fokus pada pemahaman filosofi pengujian unit dengan mensimulasikan kode pengujian unit daripada menulis pengujian unit dengan kerangka pengujian atau alat pengujian unit pihak ketiga.
Mensimulasikan Uji Unit dan Menerapkan Prinsip AAA dalam SQL
Hal pertama yang perlu kita lakukan adalah meniru prinsip AAA dalam SQL karena kita tidak akan menggunakan kerangka pengujian unit apa pun.
Bagian Assemble diterapkan ketika tabel aktual dan yang diharapkan biasanya disiapkan bersama dengan tabel yang diharapkan terisi. Kita dapat menggunakan variabel SQL untuk menginisialisasi tabel yang diharapkan pada langkah ini.
Bagian Act digunakan ketika prosedur tersimpan yang sebenarnya dipanggil untuk memasukkan data ke dalam tabel yang sebenarnya.
Bagian Tegaskan adalah saat tabel yang diharapkan cocok dengan tabel yang sebenarnya. Mensimulasikan bagian Assert sedikit rumit dan dapat dicapai dengan langkah-langkah berikut:
- Menghitung baris umum (yang cocok) antara dua tabel yang seharusnya 1 (karena tabel yang diharapkan hanya memiliki satu record yang harus cocok dengan tabel sebenarnya)
- Mengecualikan record tabel yang sebenarnya dari record tabel yang diharapkan harus sama dengan 0 (jika record di tabel yang diharapkan juga ada di tabel yang sebenarnya, maka mengecualikan semua record tabel yang sebenarnya dari tabel yang diharapkan akan menghasilkan 0)
Script SQLnya adalah sebagai berikut:
[expand title="Kode"]
-- Simulating unit test to test the AddEmployee stored procedure CREATE PROCEDURE TestAddEmployee AS BEGIN -- (1) Assemble -- Set up new employee data DECLARE @EmployeeId INT = 6 ,@NAME VARCHAR(40) = 'Adil' ,@StartDate DATETIME2 = '2018-03-01' ,@Title VARCHAR(50) = 'Development Manager' -- Set up the expected table CREATE TABLE #EmployeeExpected ( EmployeeId INT PRIMARY KEY IDENTITY (6, 1) -- the expected table EmployeeId should begin with 6 -- since the actual table has already got 5 records and -- the next EmployeeId in the actual table is 6 ,NAME VARCHAR(40) ,StartDate DATETIME2 ,Title VARCHAR(50) ); -- Add the expected table data INSERT INTO #EmployeeExpected (NAME, StartDate, Title) VALUES (@NAME, @StartDate, @Title); -- (2) Act -- Call AddEmployee to add new employee data to the Employee table INSERT INTO Employee EXEC AddEmployee @NAME ,@StartDate ,@Title -- (3) Assert -- Match the actual table with the expected table DECLARE @ActualAndExpectedTableCommonRecords INT = 0 -- we assume that expected and actual table records have nothing in common SET @ActualAndExpectedTableCommonRecords = (SELECT COUNT(*) FROM (SELECT e.EmployeeId ,e.NAME ,e.StartDate ,e.Title FROM Employee e INTERSECT SELECT ee.EmployeeId ,ee.NAME ,ee.StartDate ,ee.Title FROM #EmployeeExpected ee) AS A) DECLARE @ExpectedTableExcluldingActualTable INT = 1 -- we assume that expected table has records which do not exist in the actual table SET @ExpectedTableExcluldingActualTable = (SELECT COUNT(*) FROM (SELECT ee.EmployeeId ,ee.NAME ,ee.StartDate ,ee.Title FROM #EmployeeExpected ee EXCEPT SELECT e.EmployeeId ,e.NAME ,e.StartDate ,e.Title FROM Employee e) AS A) IF @ActualAndExpectedTableCommonRecords = 1 AND @ExpectedTableExcluldingActualTable = 0 PRINT '*** Test Passed! ***' ELSE PRINT '*** Test Failed! ***' END
[/expand]
Menjalankan Uji Unit Simulasi
Setelah prosedur tersimpan dibuat, jalankan dengan unit test simulasi:
-- Running simulated unit test to check the AddEmployee stored procedure EXEC TestAddEmployee
Outputnya adalah sebagai berikut:
Selamat! Tes unit database lulus.
Mengidentifikasi Masalah dalam bentuk Ketergantungan dalam Uji Unit
Bisakah kami mendeteksi sesuatu yang salah dalam pengujian unit yang kami buat meskipun faktanya telah ditulis dan dijalankan dengan sukses?
Jika kita melihat lebih dekat pada unit test setup (bagian Assemble), tabel yang diharapkan memiliki ikatan yang tidak perlu dengan kolom identitas:
Sebelum menulis tes unit, kami telah menambahkan 5 catatan ke tabel (Karyawan) yang sebenarnya. Jadi, pada penyiapan pengujian, kolom identitas untuk tabel yang diharapkan dimulai dengan 6. Namun, ini berarti bahwa kita selalu mengharapkan 5 record berada di tabel (Karyawan) yang sebenarnya untuk mencocokkannya dengan tabel yang diharapkan (#EmployeeExpected).
Untuk memahami bagaimana hal ini dapat memengaruhi pengujian unit, mari kita lihat tabel (Karyawan) yang sebenarnya sekarang:
Tambahkan record lain ke tabel Employee:
-- Adding a new record to the Employee table INSERT INTO Employee (NAME, StartDate, Title) VALUES ('Mark', '2018-02-01', 'Developer');
Lihat tabel Karyawan sekarang:
Hapus EmpoyeeId 6 (Adil) agar pengujian unit dapat dijalankan terhadap versi EmployeeId 6 (Adil)-nya sendiri daripada catatan yang disimpan sebelumnya.
-- Deleting the previously created EmployeeId: 6 (Adil) record from the Employee table DELETE FROM Employee WHERE EmployeeId=6
Jalankan unit test yang disimulasikan dan lihat hasilnya:
-- Running simulated unit test to check the AddEmployee stored procedure EXEC TestAddEmployee
Ujian kali ini gagal. Jawabannya terletak pada tabel hasil set Employee seperti gambar di bawah ini:
Pengikatan Employee Id pada unit test seperti yang disebutkan di atas tidak berfungsi saat kami menjalankan kembali unit test setelah menambahkan record baru dan menghapus record employee yang ditambahkan sebelumnya.
Ada tiga jenis dependensi dalam pengujian:
- Ketergantungan Data
- Ketergantungan Kendala Utama
- Ketergantungan Kolom Identitas
Ketergantungan Data
Pertama-tama, pengujian unit ini bergantung pada data dalam database. Menurut Dave Green, ketika datang ke database pengujian unit, data itu sendiri adalah ketergantungan.
Ini berarti bahwa pengujian unit database Anda tidak boleh bergantung pada data dalam database. Misalnya, pengujian unit Anda harus berisi data aktual yang akan dimasukkan ke dalam objek database (tabel) daripada mengandalkan data yang sudah ada dalam database yang dapat dihapus atau diubah.
Dalam kasus kami, fakta bahwa lima catatan telah dimasukkan ke dalam tabel Karyawan sebenarnya adalah ketergantungan data yang harus dicegah karena kami tidak boleh melanggar filosofi pengujian unit yang mengatakan hanya unit kode yang diuji.
Dengan kata lain, data pengujian tidak boleh bergantung pada data aktual dalam database.
Ketergantungan Kendala Kunci
Dependensi lain adalah dependensi batasan kunci yang berarti bahwa kolom kunci utama EmployeeId juga merupakan dependensi. Itu harus dicegah untuk menulis tes unit yang baik. Namun, pengujian unit terpisah diperlukan untuk menguji batasan kunci utama.
Misalnya, untuk menguji prosedur tersimpan AddEmployee, kunci utama tabel Karyawan harus dihapus sehingga objek dapat diuji tanpa khawatir melanggar kunci utama.
Ketergantungan Kolom Identitas
Sama seperti batasan kunci utama, kolom identitas juga merupakan ketergantungan. Jadi, tidak perlu menguji logika kenaikan otomatis kolom identitas untuk prosedur AddEmployee; itu harus dihindari dengan cara apa pun.
Mengisolasi Dependensi dalam Pengujian Unit
Kita dapat mencegah ketiga dependensi dengan menghapus batasan dari tabel sementara dan kemudian tidak bergantung pada data dalam database untuk unit test. Beginilah cara pengujian unit basis data standar ditulis.
Dalam hal ini, orang mungkin bertanya dari mana data untuk tabel Karyawan berasal. Jawabannya adalah tabel diisi dengan data pengujian yang ditentukan dalam pengujian unit.
Mengubah Prosedur Tersimpan Pengujian Unit
Sekarang mari kita hapus dependensi dalam pengujian unit kita:
[expand title="Kode"]
-- Simulating dependency free unit test to test the AddEmployee stored procedure ALTER PROCEDURE TestAddEmployee AS BEGIN -- (1) Assemble -- Set up new employee data DECLARE @NAME VARCHAR(40) = 'Adil' ,@StartDate DATETIME2 = '2018-03-01' ,@Title VARCHAR(50) = 'Development Manager' -- Set actual table DROP TABLE Employee -- drop table to remove dependencies CREATE TABLE Employee -- create a table without dependencies (PRIMARY KEY and IDENTITY(1,1)) ( EmployeeId INT DEFAULT(0) ,NAME VARCHAR(40) ,StartDate DATETIME2 ,Title VARCHAR(50) ) -- Set up the expected table without dependencies (PRIMARY KEY and IDENTITY(1,1) CREATE TABLE #EmployeeExpected ( EmployeeId INT DEFAULT(0) ,NAME VARCHAR(40) ,StartDate DATETIME2 ,Title VARCHAR(50) ) -- Add the expected table data INSERT INTO #EmployeeExpected (NAME, StartDate, Title) VALUES (@NAME, @StartDate, @Title) -- (2) Act -- Call AddEmployee to add new employee data to the Employee table EXEC AddEmployee @NAME ,@StartDate ,@Title -- (3) Assert -- Match the actual table with the expected table DECLARE @ActualAndExpectedTableCommonRecords INT = 0 -- we assume that the expected and actual table records have nothing in common SET @ActualAndExpectedTableCommonRecords = (SELECT COUNT(*) FROM (SELECT e.EmployeeId ,e.NAME ,e.StartDate ,e.Title FROM Employee e INTERSECT SELECT ee.EmployeeId ,ee.NAME ,ee.StartDate ,ee.Title FROM #EmployeeExpected ee) AS A) DECLARE @ExpectedTableExcluldingActualTable INT = 1 -- we assume that the expected table has records which donot exist in actual table SET @ExpectedTableExcluldingActualTable = (SELECT COUNT(*) FROM (SELECT ee.EmployeeId ,ee.NAME ,ee.StartDate ,ee.Title FROM #EmployeeExpected ee EXCEPT SELECT e.EmployeeId ,e.NAME ,e.StartDate ,e.Title FROM Employee e) AS A) IF @ActualAndExpectedTableCommonRecords = 1 AND @ExpectedTableExcluldingActualTable = 0 PRINT '*** Test Passed! ***' ELSE PRINT '*** Test Failed! ***' -- View the actual and expected tables before comparison SELECT e.EmployeeId ,e.NAME ,e.StartDate ,e.Title FROM Employee e SELECT ee.EmployeeId ,ee.NAME ,ee.StartDate ,ee.Title FROM #EmployeeExpected ee -- Reset the table (Put back constraints after the unit test) DROP TABLE Employee DROP TABLE #EmployeeExpected CREATE TABLE Employee ( EmployeeId INT PRIMARY KEY IDENTITY (1, 1) ,NAME VARCHAR(40) ,StartDate DATETIME2 ,Title VARCHAR(50) ); END
[/expand]
Menjalankan Uji Unit Simulasi Bebas Ketergantungan
Jalankan unit test yang disimulasikan untuk melihat hasilnya:
-- Running the dependency-free simulated unit test to check the AddEmployee stored procedure EXEC TestAddEmployee
Jalankan kembali unit test untuk memeriksa prosedur tersimpan AddEmployee:
-- Running the dependency-free simulated unit test to check the AddEmployee stored procedure EXEC TestAddEmployee
Selamat! Dependensi dari unit test telah berhasil dihapus.
Sekarang, bahkan jika kita menambahkan record baru atau kumpulan record baru ke tabel Employee, hal itu tidak akan mempengaruhi pengujian unit kita karena kita telah berhasil menghapus dependensi data dan batasan dari pengujian.
Membuat Pengujian Unit Basis Data Menggunakan tSQLt
Langkah selanjutnya adalah membuat pengujian unit basis data nyata berdasarkan pengujian unit yang disimulasikan.
Jika Anda menggunakan SSMS (SQL Server Management Studio), Anda harus menginstal kerangka kerja tSQLt, membuat kelas pengujian, dan mengaktifkan CLR sebelum menulis dan menjalankan pengujian unit.
Jika Anda menggunakan dbForge Studio untuk SQL Server, Anda dapat membuat unit test dengan mengklik kanan prosedur tersimpan AddEmployee dan kemudian mengklik “Unit Test” => “Add New Test…” seperti yang ditunjukkan di bawah ini:
Untuk menambahkan pengujian baru, isi informasi pengujian unit yang diperlukan:
Untuk menulis unit test, gunakan skrip berikut:
-- Comments here are associated with the test. -- For test case examples, see: http://tsqlt.org/user-guide/tsqlt-tutorial/ CREATE PROCEDURE [BasicTests].[test if new employee can be added] AS BEGIN --Assemble DECLARE @NAME VARCHAR(40) = 'Adil' ,@StartDate DATETIME2 = '2018-03-01' ,@Title VARCHAR(50) = 'Development Manager' EXEC tSQLt.FakeTable "dbo.Employee" -- This will create a dependency-free copy of the Employee table CREATE TABLE BasicTests.Expected -- Create the expected table ( EmployeeId INT ,NAME VARCHAR(40) ,StartDate DATETIME2 ,Title VARCHAR(50) ) -- Add the expected table data INSERT INTO BasicTests.Expected (NAME, StartDate, Title) VALUES (@NAME, @StartDate, @Title) --Act EXEC AddEmployee @Name -- Insert data into the Employee table ,@StartDate ,@Title --Assert EXEC tSQLt.AssertEqualsTable @Expected = N'BasicTests.Expected' ,@Actual = N'dbo.Employee' ,@Message = N'Actual table matched with expected table' ,@FailMsg = N'Actual table does not match with expected table' END; GO
Kemudian, jalankan pengujian unit basis data:
Selamat! Kami telah berhasil membuat dan menjalankan pengujian unit basis data yang bebas dari ketergantungan.
Hal yang Dapat Dilakukan
Itu dia. Anda siap untuk mengisolasi dependensi dari pengujian unit database dan membuat pengujian unit database bebas dari data dan dependensi kendala setelah membaca artikel ini. Hasilnya, Anda dapat meningkatkan keterampilan Anda dengan melakukan hal-hal berikut:
- Silakan coba tambahkan prosedur tersimpan Hapus Karyawan dan buat pengujian unit basis data simulasi untuk Hapus Karyawan dengan dependensi untuk melihat apakah gagal dalam kondisi tertentu
- Silakan coba tambahkan prosedur Hapus Karyawan tersimpan dan buat pengujian unit database bebas dari ketergantungan untuk melihat apakah karyawan dapat dihapus
- Silakan coba tambahkan prosedur tersimpan Cari Karyawan dan buat pengujian unit database simulasi dengan dependensi untuk melihat apakah karyawan dapat dicari
- Silakan coba tambahkan prosedur tersimpan Cari Karyawan dan buat pengujian unit database bebas dari ketergantungan untuk melihat apakah karyawan dapat dicari
- Silakan coba persyaratan yang lebih kompleks dengan membuat prosedur tersimpan untuk memenuhi persyaratan dan kemudian menulis pengujian unit basis data bebas dari dependensi untuk melihat apakah mereka lulus pengujian atau gagal. Namun, pastikan pengujian dapat diulang dan difokuskan pada pengujian unit kode
Alat yang berguna:
dbForge Unit Test – GUI yang intuitif dan nyaman untuk mengimplementasikan pengujian unit otomatis di SQL Server Management Studio.