2014-06-16 65 views
5

我有不同的行爲在不同平臺上一些特別挑剔的代碼,但也表現不同,如果valgrind下運行...現在我知道這expect_error_or_warning in testthat?

  • 發出警告,如果在32位Linux 無法運行下的valgrind
  • 給人如果在32位Linux與R -d valgrind

別處運行以下作品的代碼(對不起,缺乏再版的錯誤oducible的例子,你可能會看到,這將是很難寫一個)如果我不是在valgrind下運行,但在valgrind下失敗,因爲我們得到一個錯誤,而不是一個警告。

if (sessionInfo()$platform=="i686-pc-linux-gnu (32-bit)") { 
     expect_warning(update(g0, .~. +year), "failed to converge") 
    } else { 
     expect_error(update(g0, .~. +year), "pwrssUpdate did not converge in") 
    } 

我想要一個expect_warning_or_error()函數;我想我可以做一個通過砍掉expect_errorexpect_warning的內膽,這看起來不太複雜,但我歡迎其他建議。

或者,我可以弄清楚如何檢測我是否在valgrind下運行(看起來更難)。

重複的例子,一個排序的:

library(testthat) 
for (i in c("warning","stop")) { 
    expect_warning(get(i)("foo")) 
    expect_error(get(i)("foo")) 
} 

回答

5

我的解決方案,從gives_warning()throws_error()砍死在一起。我不知道它是完全地道/健壯......

gives_error_or_warning <- function (regexp = NULL, all = FALSE, ...) 
{ 
    function(expr) { 
     res <- try(evaluate_promise(expr),silent=TRUE) 
     no_error <- !inherits(res, "try-error") 
     if (no_error) { 
      warnings <- res$warnings 

      if (!is.null(regexp) && length(warnings) > 0) { 
       return(matches(regexp, all = FALSE, ...)(warnings)) 
      } else { 
       return(expectation(length(warnings) > 0, "no warnings or errors given", 
          paste0(length(warnings), " warnings created"))) 
      } 
     } 
     if (!is.null(regexp)) { 
      return(matches(regexp, ...)(res)) 
     } 
     else { 
      expectation(TRUE, "no error thrown", "threw an error") 
     } 
    } 
} 
3

@Ben我可能會誤解,但說到這裏介意,如果你想知道如果事情出錯/警告或者不是你可以使用tryCatch。如果這不是你想要的,或者你希望更多的方式可以隨意說「你是標誌的方式」,但添加一個表情,如:-),它會使一切變得更好。

首先我製作一個temperamental函數來模擬你描述的內容。然後,我創建一個is.bad函數,只查找錯誤或警告(不要擔心操作系統,因爲這種行爲很難預測)。然後,我expect_trueexpect_false包裝:

temperamental <- function(x) { 
    if (missing(x)){ 
     ifelse(sample(c(TRUE, FALSE), 1), stop("Robot attack"), warning("Beware of bots!")) 
    } else { 
     x 
    } 
} 

temperamental() 
temperamental(5) 

is.bad <- function(code) { 
    isTRUE(tryCatch(code, 
     error = function(c) TRUE, 
     warning = function(c) TRUE 
    )) 
} 

expect_true(is.bad(temperamental())) 
expect_false(is.bad(temperamental(5))) 
+0

這很不錯,我可以接受它。我希望有更多的「測試地道」;我正在竊聽一些不太好但我可能會發布的內容。你的確滿足基本要求。 –

1

我有同樣的問題和閱讀的兩種功能我找到了一個很好的解決方案的來源之後。其實很簡單,你只需要在expect_error的代碼中添加一個小的if語句即可。

這是expect_error

function (object, regexp = NULL, ..., info = NULL, label = NULL) 
{ 
    lab <- make_label(object, label) 
    error <- tryCatch({ 
     object 
     NULL 
    }, error = function(e) { 
     e 
    }) 
    if (identical(regexp, NA)) { 
     expect(is.null(error), sprintf("%s threw an error.\n%s", 
             lab, error$message), info = info) 
    } 
    else if (is.null(regexp) || is.null(error)) { 
     expect(!is.null(error), sprintf("%s did not throw an error.", 
             lab), info = info) 
    } 
    else { 
     expect_match(error$message, regexp, ..., info = info) 
    } 
    invisible(NULL) 
} 

代碼添加你檢查返回值之前,如果沒有拋出一個錯誤,檢查警告(記住所有的參數添加到新的功能)的if語句。新的功能代碼是這樣的:

expect_error_or_warning <- function (object, regexp = NULL, ..., info = NULL, label = NULL, all = FALSE) 
{ 
    lab <- testthat:::make_label(object, label) 
    error <- tryCatch({ 
     object 
     NULL 
    }, error = function(e) { 
     e 
    }) 

    if (identical(regexp, NA)) { 
     expect(is.null(error), sprintf("%s threw an error.\n%s", 
             lab, error$message), info = info) 
    } else if (is.null(regexp) || is.null(error)) { 
     expect(!is.null(error), sprintf("%s did not throw an error.", 
             lab), info = info) 
    } else { 
     expect_match(error$message, regexp, ..., info = info) 
    } 

    if(is.null(error)){ 
     expect_warning(object = object, regexp = regexp, ..., all = all, info = info, label = label) 
    } 
    invisible(NULL) 
} 

此代碼非常強大,易於維護。如果您正在編寫程序包並且無法使用未導出的函數(:: :),那麼您可以將make_label中的代碼帶入該函數,但只有一行。