Home > News > Breaking News > Automatizzare il test di una soluzione SQL Server con tSQLt, Docker e GitHub Actions!

Automatizzare il test di una soluzione SQL Server con tSQLt, Docker e GitHub Actions!

Nell’articolo precedente, il terzo di questa serie, abbiamo descritto come scrivere ed eseguire manualmente una unit di test per un trigger! In questo articolo verrà descritto come automatizzare il test di uno o più oggetti SQL Server utilizzando tSQLt, Docker e GitHub Actions!

Tecnologie e framework utilizzati

Le potenzialità del framework tSQLt sono state descritte nell’articolo “Il framework tSQLt e l’esecuzione di un test”:

Docker è uno dei più diffusi sistemi per l’esecuzione di applicazioni in ambienti isolabili, minimali e facilmente distribuibili chiamati container. SQL Server 2017, e le successive versioni, possono essere eseguite in un container Docker, un tipico scenario di utilizzo di container è proprio quello che riguarda l’automazione dei test.

GitHub Actions è una piattaforma di Continuous Integration e Continuous Delivery (CI/CD) che consente di automatizzare pipeline di compilazione, test e distribuzione. È possibile creare workflows in grado di compilare e testare una soluzione software ad ogni pull request o commit sul repository. Attraverso le GitHub Actions, GitHub fornisce macchine virtuali Linux, Windows e macOS per eseguire i workflows in alternativa all’utilizzo di risorse ospitate in cloud (per esempio Azure VM).

Case history

Il database AdventureWorks2017 contiene la tabella Production.Product che rappresenta l’anagrafica dei prodotti gestiti e commercializzati dall’azienda immaginaria Adventure Works LTD 😊 il cui database è disponibile per il download su questo repository GitHub. L’azienda ha commissionato lo sviluppo di un trigger per impedire l’inserimento di nuovi prodotti aventi come scorta di sicurezza valori minori di 10. L’azienda desidera quindi avere sempre una scorta di magazzino pari a 10 unità. La scorta di sicurezza è un dato molto importante per le procedure automatiche di riordino dei materiali che ne tengono conto per l’emissione degli ordini a fornitore o degli ordini di produzione. Per semplificare l’esempio, il trigger risponderà soltanto all’evento OnInsert.

Gli script TSQL per la creazione del trigger e delle relative unit di test sono disponibili all’interno del repository GitHub sql-server-demos-ci-cd, la stored procedure usp_Raiserror_SafetyStockLevel gestisce gli errori in modo centralizzato.

Automazione dello unit testing con tSQLt, Docker e GitHub Action

L’implementazione del trigger e delle relative unit di test è stata completata, la prossima sfida consiste nel rendere automatica l’esecuzione dei test ad ogni commit sul repository. Per raggiungere l’obiettivo è necessario individuare una piattaforma di Continuous Integration e Continuous Delivery in grado di supportare l’utilizzo di container.

GitHub Actions sarà la nostra piattaforma di CI/CD, supporta l’utilizzo di container Docker ed è intimamente integrata in GitHub, il source control che gestisce il versioning delle modifiche al codice sorgente. L’utilizzo di GitHub Actions non è l’unica possibilità ma per questo progetto di esempio è sicuramente la più adatta.

Procediamo con la creazione di un workflow rappresentato da un processo automatizzato e configurabile che eseguirà uno o più job. I workflow vengono definiti con un file YAML archiviato nello stesso repository che detiene il codice sorgente. I workflow verranno attivati al verificarsi di un evento nel repository (per esempio un commit).

Un workflow può anche essere attivato manualmente o in base a una pianificazione definita. Il file YAML che implementa il workflow di automazione dei test è disponibile qui, gli step fondamentali sono:

  • Definizione degli eventi di attivazione
  • Creazione di un container Docker da una immagine di SQL Server su Linux
  • Ripristino del database AdventureWorks2017
  • Installazione del framework tSQLt
  • Creazione degli oggetti database da testare (SUT)
  • Creazione ed esecuzione delle unit di test

Definizione degli eventi di attivazione

La definizione degli eventi di attivazione avviene tipicamente all’inizio dello script YAML con un frammento di codice simile a quello riportato di seguito. Il workflow si attiva al verificarsi di eventi push o pull request sul ramo “master”. La specifica workflow_dispatch consente di eseguire il workflow manualmente dalla scheda azioni.

# Controls when the workflow will run
on:
  # Triggers the workflow on push or pull request events but only for the "master" branch
  push:
    branches: [ "master" ]
  pull_request:
    branches: [ "master" ]
    
  # Allows you to run this workflow manually from the Actions tab
  workflow_dispatch:

Creazione di un container Docker da una immagine di SQL Server su Linux

La creazione di un container Docker da una immagine di SQL Server su Linux può essere eseguita richiedendo il servizio sqlserver accompagnato dal path dell’immagine Docker che si desidera utilizzare. Le immagini ufficiali, fornite da Microsoft, per SQL Server su Linux sono disponibili qui. Noi non useremo una immagine ufficiale scaricata dal registry Microsoft. Useremo l’immagine Docker, pubblicata da chriseaton, di SQL Server con il database AdventureWorks installato, la trovate a questo link. Il seguente frammento di codice YAML predispone il servizio SQL Server.

jobs:
  windows-auth-tsqlt:
    name: Installting tSQLt with SQL Auth
    # The type of runner that the job will run on
    runs-on: ubuntu-latest
    
    services:
      sqlserver:
        image: chriseaton/adventureworks:latest
        ports:
          - 1433:1433
        env:
          ACCEPT_EULA: Y
          SA_PASSWORD: 3uuiCaKxfbForrK

Per poter referenziare il container Docker appena creato è importante salvare il suo identificativo in una variabile di ambiente. Il seguente frammento di codice YAML imposta la variabile ENV_CONTAINER_ID con l’ID del container creato.

- name: Set environment variable ENV_CONTAINER_ID
  run: echo "ENV_CONTAINER_ID=$(docker ps --all --filter status=running --no-trunc --format "{{.ID}}")" >> $GITHUB_ENV

Ripristino del database AdventureWorks2017

Il ripristino del database AdventureWorks2017 viene eseguito con il seguente comando docker exec.

- name: Restore AdventureWorks2017
  run: docker exec -i $ENV_CONTAINER_ID /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "3uuiCaKxfbForrK" -Q "RESTORE DATABASE [AdventureWorks2017] FROM DISK = '/adventureworks.bak' WITH MOVE 'AdventureWorks2017' TO '/var/opt/mssql/data/AdventureWorks.mdf', MOVE 'AdventureWorks2017_log' TO '/var/opt/mssql/data/AdventureWorks_log.ldf'"

Installazione del framework tSQLt

L’installazione dell’ultima versione del framework tSQLt nel database AdventureWorks2017 viene effettuata utilizzando la GitHub Actions tSQLt Installer pubblicata da lowlydba, trovate tutti i dettagli qui e sul marketplace GitHub Actions. Il frammento di codice YAML utilizzato per l’installazione del framework tSQLt nel database AdventureWorks2017 è il seguente.

steps:
  - uses: actions/checkout@v2

  - name: Install tSQLt with SQL auth on AdventureWorks2017
    uses: lowlydba/tsqlt-installer@v1
    with:
      sql-instance: localhost
      database: AdventureWorks2017
      version: latest
      user: sa
      password: 3uuiCaKxfbForrK

Creazione degli oggetti database da testare (SUT)

L’ambiente di test è pronto, abbiamo una istanza SQL Server su Linux dentro un container Docker, il database AdventureWorks2017 è stato ripristinato ed è pronto all’uso. Procediamo con la creazione del trigger e della stored procedure (che gestisce gli errori), rappresentano il nostro System Under Test (SUT).

Lo script di creazione del trigger TR_Product_SafetyStockLevel e quello di creazione della stored procedure usp_Raiserror_SafetyStockLevel sono salvati nella directory source del repository sql-server-demos-ci-cd.

Trigger e stored procedure vengono creati nel database AdventureWorks2017 agganciato all’istanza SQL Server, il frammento di codice YAML che effettua questa operazione è il seguente.

- name: Create sp usp_Raiserror_SafetyStockLevel
  run: docker exec -i $ENV_CONTAINER_ID /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "3uuiCaKxfbForrK" -d AdventureWorks2017 -b < ./source/usp-raiserror-safetystocklevel.sql

- name: Create TR_Product_SafetyStockLevel
  run: docker exec -i $ENV_CONTAINER_ID /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "3uuiCaKxfbForrK" -d AdventureWorks2017 -b < ./source/tr_product_safetystocklevel.sql

Creazione ed esecuzione delle unit di test

L’ultima fase di questo workflow è rappresentata dalla creazione ed esecuzione delle unit di test. Gli script di creazione della classe di test e delle singole unit sono contenuti all’interno della directory unit-test del repository sql-server-demos-ci-cd. Procediamo quindi con la creazione della classe di test dedicata al trigger TR_Product_SafetyStockLevel, l’abbiamo chiamata UnitTestTRProductSafetyStockLevel. Il seguente comando docker exec, attraverso sqlcmd, manda in esecuzione i comandi TSQL contenuti nello script test-class-trproductsafetystocklevel.sql.

- name: Create test class UnitTestTRProductSafetyStockLevel
  run: docker exec -i $ENV_CONTAINER_ID /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "3uuiCaKxfbForrK" -d AdventureWorks2017 -b < ./unit-test/test-class-trproductsafetystocklevel.sql

Procediamo quindi con la creazione e l’esecuzione delle unit di test. Ogni file .sql della famiglia “test case” contenuto nella directory unit-test contiene i comandi TSQL per la creazione e l’esecuzione di una unit di test. Ogni unit di test verifica un solo test case. Per il trigger TR_Product_SafetyStockLevel abbiamo previsto quattro test case. Il seguente frammento di codice YAML crea ed esegue le unit di test previste.

- name: Create and run test case try to insert one wrong row
  run: docker exec -i $ENV_CONTAINER_ID /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "3uuiCaKxfbForrK" -d AdventureWorks2017 -b < ./unit-test/test-case-try-to-insert-one-wrong-row.sql

- name: Create and run test case try to insert one right row
  run: docker exec -i $ENV_CONTAINER_ID /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "3uuiCaKxfbForrK" -d AdventureWorks2017 -b < ./unit-test/test-case-try-to-insert-one-right-row.sql

- name: Create and run test case try to insert multiple rows
  run: docker exec -i $ENV_CONTAINER_ID /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "3uuiCaKxfbForrK" -d AdventureWorks2017 -b < ./unit-test/test-case-try-to-insert-multiple-rows.sql

- name: Create and run test case try to insert multiple rows ordered
  run: docker exec -i $ENV_CONTAINER_ID /opt/mssql-tools/bin/sqlcmd -S localhost -U SA -P "3uuiCaKxfbForrK" -d AdventureWorks2017 -b < ./unit-test/test-case-try-to-insert-multiple-rows-ordered.sql

Lo script YAML relativo al workflow di esecuzione delle unit di test è completo, lo trovate qui, non ci resta che verificarlo eseguendolo manualmente dalla scheda azioni. Il workflow verrà completato con successo se tutte le operazioni eseguite avranno dato esito positivo.

Conclusioni

Le unit di test sviluppate per una soluzione SQL Server non hanno il solo scopo di verificare che siano stati soddisfatti i requisiti una volta, prima del rilascio; il vero game changer è rappresentato dalla possibilità di ripetere le verifiche durante lo sviluppo di nuovo codice e durante la correzione di bug. La ripetibilità dei test fornisce la possibilità di automatizzarli, condizione essenziale per integrare test automatici all’interno di uno strumento di Continuous Integration.

Link utili

Chi è Sergio Govoni

Sergio Govoni è laureato in Scienze e Tecnologie Informatiche. Da oltre 16 anni lavora presso una software house che produce un noto sistema ERP, distribuito a livello nazionale ed internazionale, multi azienda client/server su piattaforma Win32. Attualmente si occupa di progettazione e analisi funzionale, coordina un team di sviluppo ed è responsabile tecnico di prodotto. Lavora con SQL Server dalla versione 7.0 e si è occupato d'implementazione e manutenzione di database relazionali in ambito gestionale, ottimizzazione delle prestazioni e problem solving. Nello staff di UGISS si dedica alla formazione e alla divulgazione in ambito SQL Server e tecnologie a esso collegate, scrivendo articoli e partecipando come speaker ai workshop e alle iniziative del primo e più importante User Group Italiano sulla tecnologia SQL Server. Ha conseguito la certificazione MCP, MCTS SQL Server. Per il suo contributo nelle comunità tecniche e per la condivisione della propria esperienza con altri, dal 2010 riceve il riconoscimento SQL Server MVP (Microsoft Most Valuable Professional). Nel corso dell'anno 2011 ha contribuito alla scrittura del libro SQL Server MVP Deep Dives Volume 2 (http://www.manning.com/delaney/).

Leggi Anche

Data Saturday Parma 2022 – Slide deck, demo e video delle sessioni

L’edizione 2022 del Data Saturday Parma si è tenuta sabato 26 novembre presso l’Università degli …