2013-01-23 17 views
6

Sto scrivendo alcuni test per un pacchetto R e vorrei che R CMD check verifichi che le funzioni visualizzino gli avvisi corretti per determinati input. Ma non riesco a capire come catturare l'output di avviso in modo da poterlo testare.Come scrivere un test del pacchetto in R per vedere se l'avviso è stato lanciato correttamente?

Quindi, se ho una funzione come:

throwsWarning<-function(x){ 
    if(x>0){ 
    warning('Argument "x" is greater than zero, results may be incorrect') 
    } 
    # do something useful ... 
} 

vorrei un qualcosa nel mio file di test come:

warningOutput <-try(throwsWarning(1)) 
if (warningOutput!='Argument "x" is greater than zero, results may be incorrect'){ 
    stop('function "throwsWarning" did not produce correct warning when x>0') 
} 

soluzioni parziali Finora ho trovato possibile modificando options in modo che gli avvertimenti vengano trattati come errori e l'ambiente circostante con un blocco trycatch. Considerato anche il valore di prova di last.warning, ma ciò sembra pericoloso se l'avvertimento non viene lanciato (proverebbe il valore precedente). Sembra che ci debba essere un modo semplice per fare questo che mi manca?

+1

Sembra che tu non stia usando 'testthat' nei test. – Spacedman

risposta

6

Il testthat package ha una funzione expect_warning e gives_warning che è possibile utilizzare.

Dagli esempi, si dovrebbe fare qualcosa di simile:

R> library(testthat) 
R> expect_that(warning("this is a warning"), gives_warning("is a")) 
## This does not raise an error, but: 
R> expect_that(warning("this is a warning"), gives_warning("nope")) 
Error: warning("this is a warning") does not match 'nope'. Actual value: 
this is a warning 

Quindi, gives_warning è un'espressione regolare che viene confrontata con l'avvertimento che dovrebbe essere emessa. Se la regex non corrisponde (o nessun avviso viene lanciato), viene sollevata una bandiera rossa.

Allo stesso modo, utilizzando il più breve expect_warning:

R> expect_warning(warning("this is a warning"), "is a") 
+1

Bello! Non posso credere di aver scritto prove per tutto questo tempo senza testarlo. Sarebbe bello se CRAN lo suggerisse nei documenti di scrittura del pacchetto. Sembra che l'unico svantaggio è l'aggiunta di una dipendenza extra solo per eseguire i test. – skyebend

+0

Felice di averti sintonizzato su un pacchetto che non era nel tuo radar, specialmente perché il pacchetto in questione è assolutamente fantastico ;-) Inoltre, metti 'testthat' nel campo' Suggests' - non ha bisogno essere in 'Depends' o' Imports', quindi si aggiungerebbe una dipendenza al pacchetto solo per quelle persone che vogliono effettivamente eseguire i test (non solo le persone che vogliono usare il pacchetto). –

2

Se si sta scrivendo il proprio pacchetto, potrebbe avere senso di fare uso del sistema di condizioni di R gettando (e cattura) particolari tipi di errori o avvisi . Così

myFun <- function(x) { 
    if (any(is.na(x))) { 
     w <- simpleWarning("'x' contains NA values") 
     class(w) <- c("HasNA", class(w)) 
     warning(w) 
    } 
    if (any(x < 0)) 
     warning("'x' contains values less than 0") 
    x 
} 

e poi nel test, ad esempio, con library(RUnit), utilizzare tryCatch e pick off solo le condizioni che siete interessati in fase di test, vale a dire, gli avvertimenti alla classe HasNA:

test_myFun_NAwarning <- function() { 
    warnOccurred <- FALSE 
    tryCatch(myFun(1:5), HasNA = function(w) warnOcccurred <<- TRUE) 
    checkTrue(!warnOccurred) 
    tryCatch(myFun(-(1:5)), HasNA = function(w) warnOcccurred <<- TRUE) 
    checkTrue(!warnOccurred) 
    tryCatch(myFun(c(1:5, NA)), HasNA = function(w) warnOccurred <<- TRUE) 
    checkTrue(warnOccurred) 
} 

leader a

> test_myFun_NAwarning() 
[1] TRUE 
Warning message: 
In myFun(-(1:5)) : 'x' contains values less than 0 

che dimostra che TryCatch sta recuperando solo l'avviso particolare che ti interessa, e di farlo in un wa y che non si basa sulla corrispondenza del testo della stringa. Forse avresti una funzione di supporto .warn per rendere tutti gli avvisi per il tuo pacchetto. Vedi ?withCallingHandlers per ulteriori dettagli; withCallingHandlers e muffleRestart sono come si potrebbe far fronte alla valutazione continua dopo un avvertimento, piuttosto che arrestare il modo in cui lo fa tryCatch.

Problemi correlati