This document discusses unit testing in PostgreSQL. It defines a unit in PostgreSQL as domains, types, functions, views, tables, and triggers. It notes some benefits of unit testing include stability and reduced time troubleshooting errors. The document provides examples of unit testing different PostgreSQL elements like functions, views with window functions, and triggers. It recommends testing more complex elements like triggers and functions first before testing simpler elements like domains and types if time allows. A key advantage of PostgreSQL unit testing is not needing mock objects since the database is directly tested.
4. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
4
who am i
Mi definisco un Solution Architect
Ho cominciato a interessarmi di informatica quando ho
trovato sotto l'albero di natale del 1980 un Commodore 64.
L'enorme quantità di ram (64k) rispetto al precedente VIC20
(5k) mi entusiasma e mi spinge a muovere primi passi nella
programmazione fino a farne la mia professione nel 1985.
Il mio interesse ora è nettamente orientato verso il mondo
del software libero, e la mia curiosità è attratta dal mondo
della Computer Aided Software Engineering e dalle
metodologie Agili.
Nel mio tempo libero mi appassiona costruire e far volare
aeromodelli.
5. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
5
who am i
Membro ATTIVO del Linux User Group di verona (http://www.lugverona.it)
Nel direttivo del Verona FABLAB (http://www.veronafablab.it)
linkedin: https://it.linkedin.com/in/andreaadami/it
Google+: https://plus.google.com/+AndreaAdamiProfile
Instagram: https://www.instagram.com/folvr
Twitter: https://twitter.com/folstuff
7. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
7
DEFINIZIONI
https://it.wikipedia.org/wiki/Unit_testing
In ingegneria del software, per unit testing (testing
d'unita o testing unitario) si intende l'attivita di testing’ ’
(prova, collaudo) di singole unita software. Per unita si’ ’
intende normalmente il minimo componente di un
programma dotato di funzionamento autonomo; a
seconda del paradigma di programmazione o
linguaggio di programmazione, questo puo’
corrispondere per esempio a una singola funzione nella
programmazione procedurale, o una singola classe o
un singolo metodo nella programmazione a oggetti.
8. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
8
COSTI / BENEFICI
●
COSTI
– INERZIA
– CODING
●
BENEFICI
– STABILITA
– TEMPO
●
all inizio di piu’ ’
●
poi si recupera
9. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
9
AMBIENTE DI PROVA
Virtual Box per virtualizzare
https://www.virtualbox.org/wiki/Downloads
10. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
10
AMBIENTE DI PROVA
Macchina virtuale con ubuntu 16.04.1 LTS
https://www.ubuntu.com/download/server
11. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
11
AMBIENTE DI PROVA
Database da GITHUB Scuola247
https://github.com/Scuola247/PostgreSQL
README.md : istruzioni per (Virtualbox/Ubuntu/PostgreSQL/Scuola247)
12. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
12
AMBIENTE DI PROVA
Scuola247 http://www.scuola247.org
README.md : istruzioni per (Virtualbox/Ubuntu/PostgreSQL/Scuola247)
13. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
13
AMBIENTE DI PROVA
MIGLIAIA di righe di dati
MIGLIAIA di photo prese da Wikimedia Commons:
https://commons.wikimedia.org/wiki/Main_Page
con documentazione della licenza per il libero utlizzo
8 schemi
64 tabelle
69 viste
32 trigger
87 funzioni
15. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
15
UNITA’ SOFTWARE
I domini di dati (Domain)
CREATE DOMAIN utility.week_day
AS smallint
CONSTRAINT week_day_range CHECK (VALUE >= 1
AND VALUE <= 7);
16. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
16
UNITA’ SOFTWARE
I tipi di dati (Type)
CREATE TYPE public.sex AS ENUM
('M',
'F');
17. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
17
UNITA’ SOFTWARE
Per chi ama la precisione:
CREATE TYPE public.sex AS ENUM
('M',
'F',
'?',
'H',
'SH',
'MC',
'FC',
'HM',
'HF',
'HT',
'I',
'A',
'X',
'O',
'MP',
'FP',
'CP');
18. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
18
UNITA’ SOFTWARE
https://de.wikipedia.org/wiki/Datenstandards_z
ur_Beschreibung_des_Geschlechts
19. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
19
UNITA’ SOFTWARE
Conversioni (Cast)
CREATE CAST (mime_type AS file_extension)
WITH FUNCTION public.file_extension(mime_type)
AS IMPLICIT;
CREATE CAST (file_extension AS mime_type)
WITH FUNCTION public.mime_type(file_extension)
AS IMPLICIT;
20. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
20
UNITA’ SOFTWARE
Le funzioni (Function)
CREATE FUNCTION utility.day_name(_weekday utility.week_day)
RETURNS character varying AS
$BODY$
<<me>>
DECLARE
function_name varchar = 'dayname';
BEGIN
RETURN to_char('2000-01-02'::date + _weekday, 'TMDay');
END;
$BODY$
21. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
21
UNITA’ SOFTWARE
Le funzioni (Function)
CREATE FUNCTION utility.day_name(_weekday utility.week_day)
RETURNS character varying AS
$BODY$
<<me>>
DECLARE
function_name varchar = 'dayname';
BEGIN
RETURN to_char('2000-01-02'::date + _weekday, 'TMDay');
END;
$BODY$
22. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
22
UNITA’ SOFTWARE
Le funzioni (Function)
CREATE OR REPLACE FUNCTION public.italian_fiscal_code(
name character varying,
surname character varying,
sex sex,
birthday date,
country_of_birth smallint,
city_of_birth character varying)
RETURNS character varying AS
$BODY$
23. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
23
UNITA’ SOFTWARE
Le viste (Views)
CREATE OR REPLACE VIEW
public.valutations_stats_classrooms_students_subjects
AS
SELECT va.classroom,
va.student,
va.subject,
min(vo.thousandths) AS min,
max(vo.thousandths) AS max,
round(avg(vo.thousandths)) AS media,
round(stddev_pop(vo.thousandths)) AS dev_std
FROM valutations va
JOIN grades vo ON vo.grade = va.grade
GROUP BY va.classroom, va.student, va.subject;
24. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
24
UNITA’ SOFTWARE
L e v i s t e ( V i e w s ) c o n w i n d o w f u n c t i o n e j o i n m u l t i p l i
C R E A T E V I E W p u b l i c . v a l u t a t i o n s _ r e f e r e n c e s A S
S E L E C T t . c l a s s r o o m ,
t . t e a c h e r ,
t . s u b j e c t ,
t . o n _ d a t e ,
t . g r a d e _ t y p e ,
t . g r a d e _ t y p e _ d e s c r i p t i o n ,
t . g r a d e _ t y p e _ m n e m o n i c ,
t . t o p i c ,
t . t o p i c _ d e s c r i p t i o n ,
t . m e t r i c ,
t . m e t r i c _ d e s c r i p t i o n ,
r o w _ n u m b e r ( ) O V E R ( P A R T I T I O N B Y t . c l a s s r o o m , t . t e a c h e r , t . s u b j e c t , t . o n _ d a t e O R D E R B Y
t . g r a d e _ t y p e _ d e s c r i p t i o n , t . t o p i c _ d e s c r i p t i o n , t . m e t r i c _ d e s c r i p t i o n ) A S r o w _ n u m b e r
F R O M ( S E L E C T D I S T I N C T v a . c l a s s r o o m ,
v a . t e a c h e r ,
v a . s u b j e c t ,
v a . o n _ d a t e ,
v a . g r a d e _ t y p e ,
t v . d e s c r i p t i o n A S g r a d e _ t y p e _ d e s c r i p t i o n ,
t v . m n e m o n i c A S g r a d e _ t y p e _ m n e m o n i c ,
v a . t o p i c ,
C O A L E S C E ( a . d e s c r i p t i o n , ' ' : : c h a r a c t e r v a r y i n g ) A S t o p i c _ d e s c r i p t i o n ,
m . m e t r i c ,
m . d e s c r i p t i o n A S m e t r i c _ d e s c r i p t i o n
F R O M v a l u t a t i o n s v a
L E F T J O I N t o p i c s a O N a . t o p i c = v a . t o p i c
J O I N g r a d e _ t y p e s t v O N t v . g r a d e _ t y p e = v a . g r a d e _ t y p e
J O I N g r a d e s v o O N v o . g r a d e = v a . g r a d e
J O I N m e t r i c s m O N m . m e t r i c = v o . m e t r i c
O R D E R B Y v a . o n _ d a t e , t v . d e s c r i p t i o n , ( C O A L E S C E ( a . d e s c r i p t i o n , ' ' : : c h a r a c t e r v a r y i n g ) ) , m . d e s c r i p t i o n ) t ;
25. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
25
UNITA’ SOFTWARE
Le viste (Views) con crosstab function
CREATE OR REPLACE VIEW
unit_testing.tests_check_points_count_crosstab AS
SELECT crosstab.test,
COALESCE(crosstab."Failed", 0) AS "Failed",
COALESCE(crosstab."Passed", 0) AS "Passed",
COALESCE(crosstab."Skipped", 0) AS "Skipped",
COALESCE(crosstab."Failed", 0) +
COALESCE(crosstab."Passed", 0) + COALESCE(crosstab."Skipped",
0) AS "Total"
FROM crosstab('SELECT test, status, count FROM
unit_testing.tests_check_points_count ORDER BY 1'::text,
'SELECT enum_value FROM utility.enums_values WHERE
schema_name = ''unit_testing'' AND enum_name =
''check_point_status'' ORDER BY 1'::text) crosstab(test
integer, "Failed" integer, "Passed" integer, "Skipped"
integer);
26. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
26
UNITA’ SOFTWARE
Le tabelle (Tables)
● CONSTRAINT NULL (NOT NULL)
● CONSTRAINT DEFAULT
● CONSTRAINT UNIQUE
● CONSTRAINT CHECK
● CONSTRAINT REFERENCES
● EXCLUDE
27. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
27
CREATE TABLE public.school_years
(
school_year bigint NOT NULL DEFAULT nextval('pk_seq'::regclass),
school bigint NOT NULL,
description character varying(160) NOT NULL,
duration daterange,
lessons_duration daterange,
CONSTRAINT school_years_pk PRIMARY KEY (school_year),
CONSTRAINT school_years_fk_school FOREIGN KEY (school)
REFERENCES public.schools (school) MATCH SIMPLE
ON UPDATE CASCADE ON DELETE RESTRICT,
CONSTRAINT school_years_ex_duration EXCLUDE
USING gist (school WITH =, duration WITH &&), -- in the same school we cannot have
duration overlap
CONSTRAINT school_years_uq_description UNIQUE (school, description), -- description
must be unique
CONSTRAINT school_years_ck_duration CHECK (duration @> lessons_duration)
)
UNITA’ SOFTWARE
28. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
28
UNITA’ SOFTWARE
I trigger (Always Function)
IF new.behavior IS NOT NULL THEN
IF (TG_OP = 'UPDATE') THEN
-- check that subject's school as equal as school
PERFORM 1 FROM subjects WHERE subject = new.behavior
AND school = new.school;
IF NOT FOUND THEN
RAISE EXCEPTION USING ......
END IF;
ELSE
--
-- cannot set the behavior because it needs school. You must:
-- 1) insert school
-- 2) insert subject
-- 3) update school with the subject
--
RAISE EXCEPTION USING ...
END IF;
END IF;
RETURN NEW;
29. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
29
COSA TESTARE ?
●
Attenzione a non testare PostgreSQL
●
Testate le cose piu difficili’
– TRIGGER
– FUNCTION
– FOREIGN KEY
●
Poi se avete tempo e voglia
– Domains
– Types
30. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
30
DIFFERENZE CON
ALTRI LINGUAGGI
POCHE
TEMPO DEDICATO PROPORZIONALMENTE
UGUALE TENDENTE A DIMINUIRE PER
1 GRANDE VANTAGGIO
32. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
32
MOCK OBJECT
https://en.wikipedia.org/wiki/Mock_object
In object-oriented programming, mock objects
are simulated objects that mimic the behavior
of real objects in controlled ways. A
programmer typically creates a mock object to
test the behavior of some other object, in much
the same way that a car designer uses a crash
test dummy to simulate the dynamic behavior
of a human in vehicle impacts.
34. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
34
1 GRANDE VANTAGGIO
BEGIN
test1
test2
tes3
testn
RAISE EXCEPTION SQLSTATE 'ZZZZZ';
EXCEPTION WHEN SQLSTATE 'ZZZZZ'
END;
35. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
35
TEST FRAMEWORKS
https://wiki.postgresql.org/wiki/Test_Frameworks
Epic
pgTap
PGUnit
Simple pgunit
36. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
36
PLPGUNIT
Un grazie a Binod Nirvan:
https://np.linkedin.com/in/binodnirvan
https://github.com/mixerp/plpgunit
37. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
37
PLPGUNIT
Problemi:
●
Il comando di lancio dei test non usa le
transazioni
●
Si puo racchiudere il comando in una’
transazione ma anche i dati risultanti dai test
vengono ripristinati (quindi persi)
●
Poco dettaglio in caso di errore non previsto
●
Poco dettaglio del singolo test
38. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
38
UNIT_TESTING
(il framework)
●
Ogni test fatto e un checkpoint’
●
I checkpoint sono raggruppati in function di
unit test
●
Le unit test function hanno una caratteristica
fondamentale:
ritornano: array di unit_test_result
●
Il framework automaticamente gestisce il
richiamo di tutte le unit_test functions in un
unica transazione che viene SEMPRE abortita
39. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
39
UNIT_TESTING
(il framework)
●
Si possono dichiarare dipendenze fra
unit_tests usando la tabella dependencies
●
Il framework poi si occupa di richiamare
nell ordine dichiarato le singole unit test’
●
Se una unit test fallisce il framework
automaticamente salta tutte le unit test che
dipendono da quella fallita
●
Il framework controlla eventuali riferimenti
circolari infiniti
40. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
40
UNIT_TESTING
(il framework)
*Si possono costituire unit test set per limitare il
richiamo di unit test function (comodo durante lo
sviluppo di una funzione per limitare i messaggi
informativi)
* da sviluppare
41. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
41
UNIT_TESTING
(il framework)
●
SCHEMAS
– assert
– diagnostic
– unit_testing
– unit_tests
– utility
43. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
43
UNIT_TESTING
(il framework)
Sintassi completa:
unit_testing.run(
IN _check_functions boolean DEFAULT FALSE,
IN _check_queries boolean DEFAULT FALSE,
IN _check_unit_tests boolean DEFAULT TRUE,
IN _unit_test_set bigint DEFAULT NULL::bigint,
IN _verbosity text DEFAULT 'notice'::text,
IN _note text DEFAULT NULL::text,
OUT _current_test bigint)
44. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
44
UNIT_TESTING
(il framework)
parametro:
check_functions = TRUE / FALSE
equivale all’ esecuzione o meno di:
SELECT * FROM diagnostic.functions_check;
46. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
46
UNIT_TESTING
(il framework)
parametro:
check_queries = TRUE / FALSE
equivale all’ esecuzione o meno di:
SELECT * FROM diagnostic.diagnostic.views_working;
47. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
47
UNIT_TESTING
(il framework)
parametro:
check_unit_tests = TRUE / FALSE
se FALSE non esegue alcuna test, se TRUE si ’
48. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
48
UNIT_TESTING
(il framework)
parametro:
*unit_test_set = <unit test set>
limita i test eseguit a quelli elencati nella unit_test_set indicata
e relative dipendenze
*da sviluppare
49. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
49
UNIT_TESTING
(il framework)
parametro:
verbosity = <verbosity level>
equivale all’ esecuzione di:
SET CLIENT_MIN_MESSAGES TO <verbosity level>
Controls which message levels are sent to the client. Valid values are
DEBUG5, DEBUG4, DEBUG3, DEBUG2, DEBUG1, LOG, NOTICE, WARNING, ERROR,
FATAL, and PANIC. Each level includes all the levels that follow it. The
later the level, the fewer messages are sent. The default is NOTICE. Note
that LOG has a different rank here than in log_min_messages.
51. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
51
UNIT_TESTING
(il framework)
parametro:
note = <note text>
Riporta il valore del parametro nella colonna noe della tabella‘ ’
unit_tests dove vengono memorizzati tutti i test eseguit
52. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
52
UNIT_TESTING
(il framework)
Risultato:
NOTIFICA: --------------------------------
NOTIFICA: ---------- STATISTICS ----------
NOTIFICA: --------------------------------
NOTIFICA: Test id.........................: 773
NOTIFICA: Test started on.................: 2016-12-13 11:45:03.381946
NOTIFICA: Test ended on...................: 2016-12-13 11:45:03.409572
NOTIFICA: Test runtime was................: 00:00:00.027626
NOTIFICA: total functions............: 3
NOTIFICA: functions passed...........: 0
NOTIFICA: functions failed...........: 1
NOTIFICA: functions skipped..........: 2
NOTIFICA: total check points....: 4
NOTIFICA: check points passed...: 2
NOTIFICA: check points failed...: 2
54. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
54
CONTINOUS
INTEGRATION
https://en.wikipedia.org/wiki/Continuous_integration
In software engineering, continuous integration (CI)
is the practice of merging all developer working
copies to a shared mainline several times a day.
Grady Booch first named and proposed CI in his
1991 method, although he did not advocate
integrating several times a day. Extreme
programming (XP) adopted the concept of CI
and did advocate integrating more than once per
day - perhaps as many as tens of times per day.
55. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
55
CONTINOUS
INTEGRATION
CREATE EVENT TRIGGER
continuous_integration ON ddl_command_end
WHEN TAG IN ('ALTER FUNCTION')
EXECUTE PROCEDURE
unit_testing.tr_continuous_integration();
56. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
56
CONTINOUS
INTEGRATION
CREATE EVENT TRIGGER continuous_integration
ON ddl_command_end
WHEN TAG IN ('ALTER FUNCTION')
EXECUTE PROCEDURE unit_testing.tr_continuous_integration();
57. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
57
FUTURO ?
●
Implementare la gestione di unit_test_set
●
Arricchire lo schema assert con nuove
funzioni dedicate a semplificare l uso del’
framework
58. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
58
CONTENUTI
Tutto quanto avete visto oggi sara su:’
Slide:
http://www.slideshare.net/andreaadami
Codice:
https://github.com/Scuola247/PostgreSQL
(comprese le istruzioni per riprodurre tutto l ambiente oggi usato)’
60. Andrea Adami (fol@fulcro.net)
P G D A Y 2 0 1 6
60
GRAZIE PER
L ATTENZIONE’
Quest opera e da attribuire a:’ ’
Andrea Adami ( http://www.folstuff.eu)
Eccetto quando diversamente indicato quest opera e licenziata con la licenza:’ ’
Creative Commons Attribuzione - Condividi allo stesso modo 4.0 Internazionale
http://creativecommons.org/licenses/by-sa/4.0 (testo completo della licenza)