Booleani
I due valori booleani sono: "true" (vero) e "false" (falso). Rispettivamente #t
o #true
e #f
o #false
in Guile.
Nel contesto di un test condizionale, "true" è una qualsiasi espressione che non sia #f
(o #false
).
Ti invito a creare una nuova directory nello spazio di lavoro dedicata a questo capitolo: ~/Workspace/guile-handbook/booleans
.
Scrivere il primo test
Crea il file booleans-test.scm
:
(use-modules (srfi srfi-64)
(booleans))
(test-begin "harness")
(test-equal "true-inverted-returns-false"
#f
(boolean-invert #t))
(test-end "harness")
Provare ed eseguire il test
guile -L . booleans-test.scm
Errore di compilazione!
;;; note: auto-compilation is enabled, set GUILE_AUTO_COMPILE=0
;;; or pass the --no-auto-compile argument to disable.
;;; compiling /home/jeko/Workspace/guile-handbook/booleans/booleans-test.scm
;;; WARNING: compilation of /home/jeko/Workspace/guile-handbook/booleans/booleans-test.scm failed:
;;; no code for module (booleans)
Scrivere la quantità minima di codice per l'esecuzione del test e controllare l'output del test non riuscito
Gli errori di compilazione possono essere visti come test "red". Nella tradizione del TDD, è essenziale aggiungere solo il minimo indispensabile di codice per correggere questi errori.
Qui, il compilatore indica che il modulo booleans
non esiste. Lo creo per correggere questo errore e riavvio immediatamente il test.
Crea il file booleans.scm
:
(define-module (booleans))
Si verifica un nuovo errore! Questa volta compila, ma mi viene segnalato che la variabile boolean-invert
non è collegata (cioè non è definita). La aggiungo al mio modulo, creato in precedenza, e rieseguo il test.
Edita il file booleans.scm
:
(define-module (booleans))
(define-public (boolean-invert bool)
0)
Non ci sono più errori o avvertimenti in fase di compilazione. Il test fallisce e si può verificare il motivo del fallimento nel file report harness.log
. Una rapida occhiata conferma che la ragione del fallimento è che il test true-inverted-returns-false
si aspetta un valore #f
mentre la procedura boolean-invert
restituisce sempre 0
.
$ cat harness.log
%%%% Starting test harness
Group begin: harness
Test begin:
test-name: "true-inverted-returns-false"
source-file: "booleans-test.scm"
source-line: 6
source-form: (test-equal "true-inverted-returns-false" #f (boolean-invert #t))
Test end:
result-kind: fail
actual-value: 0
expected-value: #f
Group end: harness
# of unexpected failures 1
Scrivere abbastanza codice per farlo passare
Modifico la procedura boolean-invert
in modo che restituisca il valore #f
come previsto dal test.
Modifica il file booleans.scm
:
(define-module (booleans))
(define-public (boolean-invert bool)
#f)
L'esecuzione del test visualizza il seguente messaggio:
$ guile -L . booleans-test.scm
;;; note: source file /home/jeko/Workspace/guile-handbook/booleans/booleans-test.scm
;;; newer than compiled /home/jeko/.cache/guile/ccache/3.0-LE-8-4.3/home/jeko/Workspace/guile-handbook/booleans/booleans-test.scm.go
;;; note: auto-compilation is enabled, set GUILE_AUTO_COMPILE=0
;;; or pass the --no-auto-compile argument to disable.
;;; compiling /home/jeko/Workspace/guile-handbook/booleans/booleans-test.scm
;;; compiled /home/jeko/.cache/guile/ccache/3.0-LE-8-4.3/home/jeko/Workspace/guile-handbook/booleans/booleans-test.scm.go
%%%% Starting test harness (Writing full log to "harness.log")
# of expected passes 1
Il test è stato superato!
Refactor
Non c'è molto da fare per così poco codice.
Docstrings
Colgo l'occasione per parlarti delle docstrings. Queste stringhe forniscono una piccola spiegazione all'utente, se necessario:
- in REPL, con il comando
,describe
. - in Emacs
Si tratta di stringhe collocate in seconda posizione nell'elenco dei parametri quando si definisce una variabile o una procedura con define
, define*
o define-public
(e via dicendo).
Aggiungiamo una docstring alla procedura boolean-invert
!
Modifica il file booleans.scm
:
(define-module (booleans))
(define-public (boolean-invert bool)
"Returns the opposite value of the given boolean."
#f)
Scrivere il primo test
Il primo test ha verificato che la chiamata alla procedura boolean-invert
con il valore #t
restituisce #f
. Il prossimo test verificherà la situazione inversa.
Modifica il file booleans-test.scm
:
(use-modules (srfi srfi-64)
(booleans))
(test-begin "harness")
(test-equal "true-inverted-returns-false"
#f
(boolean-invert #t))
(test-equal "false-inverted-returns-true"
#t
(boolean-invert #f))
(test-end "harness")
Provare a eseguire il test
$ guile -L . booleans-test.scm
Viene compilato senza nessun problema!
Scrivere la quantità minima di codice per l'esecuzione del test e controllare l'output del test non riuscito.
È possibile vedere il nuovo test che fallisce.
booleans-test.scm:10: FAIL false-inverted-returns-true
Verifica che il motivo del fallimento sia quello atteso. Ossia, il test false-inverted-returns-true
si aspetta il valore #t
ma riceve #f
.
Test begin:
test-name: "false-inverted-returns-true"
source-file: "booleans-test.scm"
source-line: 10
source-form: (test-equal "false-inverted-returns-true" #t (boolean-invert #f))
Test end:
result-kind: fail
actual-value: #f
expected-value: #t
Questo è confermato.
Scrivere abbastanza codice per farlo passare
Aggiungiamo il codice minimo e indispensabile richiesto per passare il test:
(define-module (booleans))
(define-public (boolean-invert bool)
"Returns the opposite value of the given boolean."
(if bool
#f
#t))
Lanciamo ancora il test…
%%%% Starting test harness (Writing full log to "harness.log")
# of expected passes 2
Tutto perfetto!
Refactor
Come puoi intuire, esiste una procedura già pronta per l'inversione di un dato booleano:
(define-module (booleans))
(define-public (boolean-invert bool)
"Returns the opposite value of the given boolean."
(not bool))
Riavvio i test un'ultima volta per verificare che la modifica non abbia danneggiato nulla:
%%%% Starting test harness (Writing full log to "harness.log")
# of expected passes 2
Fatto.
Conclusione
Cosa è stato trattato in questo capitolo:
- Abbiamo praticato maggiormente TDD
- Nozioni sui booleani
- Scrivere codice auto-documentato grazie alle docstrings