Database
 sql >> Teknologi Basis Data >  >> RDS >> Database

Seni Mengisolasi Dependensi dan Data dalam Pengujian Unit Basis Data

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:

  1. Mengatur/Merakit
  2. Bertindak
  3. 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:

  1. Ketergantungan Data
  2. Ketergantungan Kendala Utama
  3. 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:

  1. 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
  2. Silakan coba tambahkan prosedur Hapus Karyawan tersimpan dan buat pengujian unit database bebas dari ketergantungan untuk melihat apakah karyawan dapat dihapus
  3. Silakan coba tambahkan prosedur tersimpan Cari Karyawan dan buat pengujian unit database simulasi dengan dependensi untuk melihat apakah karyawan dapat dicari
  4. Silakan coba tambahkan prosedur tersimpan Cari Karyawan dan buat pengujian unit database bebas dari ketergantungan untuk melihat apakah karyawan dapat dicari
  5. 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.


  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Menghilangkan Duplikasi Ekspresi Where dalam Aplikasi

  2. WhoIsActive Runner

  3. Cara Melindungi Aplikasi JDBC Terhadap Injeksi SQL

  4. Menangani Nilai NULL Secara Efektif dengan Fungsi SQL COALESCE untuk Pemula

  5. Rahasia Kotor dari Ekspresi KASUS