Ruby è idiomatico aggiungere un metodo assert () alla classe Kernel di Ruby?
Domanda
Sto espandendo la mia comprensione di Ruby codificando un equivalente della xUnit di Kent Beck in Ruby. Python (in cui Kent scrive) ha un metodo assert () nel linguaggio che viene ampiamente utilizzato. Ruby no. Penso che dovrebbe essere facile aggiungere questo, ma Kernel è il posto giusto per dirlo?
A proposito, So dell'esistenza dei vari framework Unit in Ruby - questo è un esercizio per imparare gli idiomi di Ruby, piuttosto che "fare qualcosa".
Soluzione
No, non è una buona pratica. La migliore analogia da asserire () in Ruby sta solo aumentando
raise "This is wrong" unless expr
e puoi implementare le tue eccezioni se desideri fornire una gestione delle eccezioni più specifica
Altri suggerimenti
Penso che sia assolutamente valido usare assert in Ruby. Ma stai citando due cose diverse:
- I framework xUnit utilizzano i metodi
assert
per verificare le aspettative dei test. Devono essere utilizzati nel codice di test, non nel codice dell'applicazione. - Alcuni linguaggi come C, Java o Python, includono una costruzione
assert
destinata ad essere utilizzata all'interno del codice dei programmi, per verificare le ipotesi formulate in merito alla loro integrità. Questi controlli sono integrati nel codice stesso. Non sono un'utilità in fase di test, ma in fase di sviluppo.
Di recente ho scritto solid_assert: una piccola libreria di Ruby che implementa un'utilità di asserzione di Ruby e anche un post nel mio blog che spiega la sua motivazione .. Lascia scrivi espressioni nel formato:
assert some_string != "some value"
assert clients.empty?, "Isn't the clients list empty?"
invariant "Lists with different sizes?" do
one_variable = calculate_some_value
other_variable = calculate_some_other_value
one_variable > other_variable
end
E possono essere disattivati ??in modo che asserisci
e invariant
vengano valutati come istruzioni vuote. Ciò consente di evitare qualsiasi problema di prestazioni in produzione. Tuttavia, I programmatori pragmatici sconsigliano di disattivarli. Dovresti disattivarli solo se incidono davvero sulla performance.
Per quanto riguarda la risposta che dice che il modo Rubi idiomatico sta usando una normale istruzione raise
, penso che manchi di espressività. Una delle regole d'oro della programmazione assertiva non è l'uso delle asserzioni per la normale gestione delle eccezioni. Sono due cose completamente diverse. Se usi la stessa sintassi per entrambi, penso che il tuo codice sarà più oscuro. E ovviamente perdi la capacità di disattivarli.
Puoi essere convinto che usare le asserzioni sia una buona cosa perché due libri classici da leggere come The Pragmatic Programmer From Journeyman to Master e Codice completo dedica tutto sezioni a loro e raccomandarne l'uso. C'è anche un bell'articolo intitolato Programmazione con asserzioni che illustra molto bene la programmazione assertiva e quando usarla (è basata su Java, ma i concetti si applicano a qualsiasi linguaggio).
Qual è il motivo per cui hai aggiunto il metodo assert al modulo Kernel? Perché non usare semplicemente un altro modulo chiamato Assertions
o qualcosa del genere?
In questo modo:
module Assertions
def assert(param)
# do something with param
end
# define more assertions here
end
Se hai davvero bisogno che le tue affermazioni siano disponibili ovunque fai qualcosa del genere:
class Object
include Assertions
end
Disclaimer: non ho testato il codice ma in linea di principio lo farei così.
Non è particolarmente idiomatico, ma penso sia una buona idea. Soprattutto se fatto così:
def assert(msg=nil)
if DEBUG
raise msg || "Assertion failed!" unless yield
end
end
In questo modo non ha alcun impatto se decidi di non eseguire DEBUG (o qualche altro comodo switch, ho usato Kernel.do_assert in passato) set.
La mia comprensione è che stai scrivendo la tua suite di test come un modo per familiarizzare con Ruby. Quindi, mentre Test :: Unit potrebbe essere utile come guida, probabilmente non è quello che stai cercando (perché ha già fatto il lavoro).
Detto questo, l'affermazione di Python è (almeno per me) più analoga a quella di C affermare (3) . Non è specificamente progettato per test unitari, piuttosto per individuare casi in cui "ciò non dovrebbe mai accadere".
In che modo i test unitari integrati di Ruby tendono a visualizzare il problema, quindi, è che ogni singola classe di test case è una sottoclasse di TestCase , e che include un" assert " dichiarazione che verifica la validità di ciò che gli è stato passato e lo registra per la segnalazione.