2013-01-23 3 views
6

Ich schreibe einige Tests für ein R-Paket und möchte R CMD check überprüfen, dass Funktionen die richtigen Warnungen für bestimmte Eingaben anzeigen. Aber ich kann nicht herausfinden, wie ich die Warnausgabe erfassen soll, damit ich sie testen kann.Wie schreibe ich einen Paket-Test in R, um zu sehen, ob die Warnung korrekt ausgelöst wird?

Also, wenn ich eine Funktion wie:

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

ich wie ein etwas in meiner Testdatei wollen würde:

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

Bisher habe ich gefunden mögliche Teillösungen durch options Wechsel damit Warnungen als Fehler und die Umgebung mit einem trycatch Block behandelt werden. Wird auch als Testwert von last.warning betrachtet, aber das erscheint gefährlich, wenn die Warnung nicht ausgelöst wird (würde den vorherigen Wert testen). Scheint so, als müsste es eine einfache Möglichkeit geben, das zu tun, was ich vermisse?

+1

Sie scheinen 'testthat' in Ihren Tests nicht zu verwenden. – Spacedman

Antwort

6

Die testthat package hat eine expect_warning und gives_warning Funktion, die Sie verwenden können.

Aus den Beispielen, würden Sie so etwas tun:

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 

So gives_warning ist regulärer Ausdruck, der gegen die Warnung angepasst ist, die angeblich emittiert werden. Wenn die Regex nicht übereinstimmt (oder keine Warnung ausgelöst wird), wird eine rote Flagge ausgelöst.

Ebenso mit der kürzeren expect_warning:

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

Schön! Ich kann nicht glauben, dass ich die ganze Zeit Tests ohne Test geschrieben habe. Wäre toll, wenn CRAN es in der Package zum Schreiben von Dokumenten vorschlagen würde. Es scheint, als ob der einzige Nachteil darin besteht, eine zusätzliche Abhängigkeit hinzuzufügen, nur um die Tests auszuführen. – skyebend

+0

Ich bin froh, Sie auf ein Paket eingestellt zu haben, das nicht auf Ihrem Radar war - vor allem, weil das fragliche Paket total genial ist ;-) Stellen Sie "testthat" auch in das Feld "Suggests" - es braucht es nicht in 'Depends' oder' Imports' zu sein, also würden Sie dem Paket nur eine Abhängigkeit hinzufügen für jene Leute, die die Tests tatsächlich ausführen wollen (nicht nur Leute, die Ihr Paket benutzen wollen). –

2

Wenn Sie Ihr eigenes Paket schreiben, könnte es sinnvoll, den Einsatz von R Zustand System zu machen durch das Werfen (und fangen) bestimmte Arten von Fehlern oder Warnungen . So

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 
} 

und dann in Ihrem Test, zum Beispiel mit library(RUnit), verwenden tryCatch und nur die Bedingungen pflücken, die Sie bei der Prüfung interessiert sind, dh Warnungen mit Klasse 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) 
} 

führenden zu

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

die zeigt, dass TryCatch nur die besondere Warnung holt Sie interessiert sind, und so in einem wa tun y, das nicht darauf angewiesen ist, den Text der Zeichenfolge zu vergleichen. Vielleicht haben Sie eine Hilfsfunktion .warn, um alle Warnungen für Ihr Paket zu machen. Weitere Details finden Sie unter ?withCallingHandlers. withCallingHandlers und muffleRestart sind, wie man mit der fortlaufenden Bewertung nach dem Auftreten einer Warnung zurechtkommen könnte, statt den Weg zu stoppen, wie es tryCatch tut.

Verwandte Themen