2013-01-23 13 views
6

Piszę niektóre testy dla pakietu R i chciałbym mieć R CMD check sprawdzić, czy funkcje wyświetlają prawidłowe ostrzeżenia dla niektórych wejść. Ale nie mogę wymyślić, jak przechwycić wynik ostrzeżenia, aby go przetestować.Jak napisać test pakietu w R, aby zobaczyć, czy ostrzeżenie jest poprawnie zgłaszane?

Więc jeśli mam funkcji, takich jak:

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

chciałbym się coś w moim pliku testowego jak:

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') 
} 

tej pory znalazłem możliwych rozwiązań cząstkowych zmieniając options tak, że ostrzeżenia są traktowane jako błędy i otoczenie z blokiem trycatch. Również uznano testowanie wartości last.warning, ale wydaje się to niebezpieczne, jeśli ostrzeżenie nie zostanie wygenerowane (przetestuje poprzednią wartość). Wydaje się, że musi być łatwy sposób na zrobienie tego, czego mi brakuje?

+1

Wydaje się, że nie używasz 'testthat' w swoich testach. – Spacedman

Odpowiedz

6

Funkcja testthat package ma funkcję expect_warning i i .

Z przykładów, by zrobić coś takiego:

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 

Więc gives_warning jest wyrażenie regularne, która jest porównywana z ostrzeżeniem, że ma być emitowany. Jeśli wyrażenie regularne nie pasuje (lub nie jest generowane żadne ostrzeżenie), zostaje podniesiona czerwona flaga.

Podobnie, stosując krótszy expect_warning:

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

Lovely! Nie mogę uwierzyć, że pisałem testy przez cały ten czas bez testu. Byłoby wspaniale, gdyby CRAN zasugerował to w pismach do pisania paczek. Wydaje się, że jedyną wadą jest dodanie dodatkowej zależności tylko po to, aby uruchomić testy. – skyebend

+0

Cieszę się, że dostrajałem Cię do pakietu, który nie był na twoim radarze - zwłaszcza, że ​​dany pakiet jest całkowicie niesamowity ;-) Ponadto, umieść 'testthat' w polu' Suggests' - nie potrzebuje być w 'Zależności' lub' Importowaniu', więc dodawałbyś tylko zależność do pakietu dla tych osób, które faktycznie chcą uruchomić testy (nie tylko ludzie, którzy chcą użyć twojego pakietu). –

2

Jeśli piszesz swój własny pakiet, to może mieć sens, aby skorzystać z systemu stan R poprzez rzucanie (i wzrok) poszczególnych typów błędów i ostrzeżeń . Więc

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 
} 

a następnie w teście, na przykład, z library(RUnit) użyć tryCatch i zdzierać tylko warunki, które Cię interesują w testach, tj ostrzeżenia z klasą 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) 
} 

prowadzącej do:

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

, która pokazuje, że tryCatch łapie właśnie ostrzeżenie, które Cię interesuje, i robi to w y, która nie polega na dopasowywaniu tekstu ciągu. Może masz funkcję pomocnika .warn, aby wykonać wszystkie ostrzeżenia dotyczące paczki. Aby uzyskać dodatkowe informacje, patrz ?withCallingHandlers; withCallingHandlers i muffleRestart są tym, w jaki sposób można poradzić sobie z ciągłą oceną po wystąpieniu ostrzeżenia, zamiast przerywać sposób, w jaki robi to tryCatch.

Powiązane problemy