2013-01-23 13 views
6

Tôi đang viết một số kiểm tra cho gói R và muốn có R CMD check xác minh rằng các chức năng hiển thị cảnh báo chính xác cho một số đầu vào nhất định. Nhưng tôi không thể tìm ra cách nắm bắt đầu ra cảnh báo để tôi có thể kiểm tra nó.Làm thế nào để viết một gói kiểm tra trong R để xem nếu cảnh báo được ném một cách chính xác?

Vì vậy, nếu tôi có một chức năng như:

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

Tôi muốn một cái gì đó trong tập tin thử nghiệm của tôi như sau:

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

Cho đến nay tôi đã tìm thấy các giải pháp phần càng tốt bằng cách thay đổi options để cảnh báo được coi là lỗi và xung quanh với khối trycatch. Cũng được coi là giá trị thử nghiệm của last.warning, nhưng điều đó có vẻ nguy hiểm nếu cảnh báo không được ném (sẽ kiểm tra giá trị trước đó). Có vẻ như có một cách dễ dàng để làm điều này mà tôi đang thiếu?

+1

Bạn dường như không sử dụng 'testthat' trong các bài kiểm tra của mình. – Spacedman

Trả lời

6

testthat package có chức năng expect_warninggives_warning mà bạn có thể sử dụng.

Từ các ví dụ, bạn sẽ làm một cái gì đó như thế này:

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 

Vì vậy, gives_warning là biểu thức chính quy được khớp với cảnh báo rằng là vụ phải được phát ra. Nếu regex không khớp (hoặc không có cảnh báo nào được ném), thì cờ đỏ được nâng lên.

Tương tự, bằng cách sử dụng ngắn hơn expect_warning:

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

Đáng yêu! Tôi không thể tin rằng tôi đã viết bài kiểm tra tất cả thời gian này mà không cần testthat. Sẽ tuyệt vời nếu CRAN đề xuất nó trong tài liệu viết gói. Có vẻ như nhược điểm duy nhất là thêm một phụ thuộc chỉ để chạy các bài kiểm tra. – skyebend

+0

Vui mừng khi bạn đã điều chỉnh gói hàng không nằm trên radar của bạn - đặc biệt là vì gói được đề cập hoàn toàn tuyệt vời ;-) Ngoài ra, hãy đặt 'testthat' vào trường' Đề xuất' - nó không cần để ở trong 'Depends' hoặc' Imports', vì vậy bạn sẽ chỉ thêm phụ thuộc vào gói cho những người thực sự muốn chạy thử nghiệm (không chỉ những người muốn sử dụng gói của bạn). –

2

Nếu bạn đang viết gói riêng của bạn, nó có thể làm cho tinh thần để tận dụng hệ thống điều kiện R bằng cách ném (và bắt) các loại cụ thể của lỗi hoặc cảnh báo . Vì vậy,

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 
} 

và sau đó trong thử nghiệm của bạn, ví dụ, với library(RUnit), sử dụng tryCatch và chọn ra chỉ là điều kiện mà bạn quan tâm trong thử nghiệm, tức là cảnh báo với lớp 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) 
} 

hàng đầu đến

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

cho thấy tryCatch chỉ bắt gặp cảnh báo cụ thể mà bạn quan tâm và thực hiện điều đó trong wa y không dựa vào kết hợp văn bản của chuỗi. Có thể bạn sẽ có chức năng trợ giúp .warn để thực hiện tất cả cảnh báo cho gói của bạn. Xem ?withCallingHandlers để biết thêm chi tiết; withCallingHandlersmuffleRestart là cách người ta có thể đối phó với việc đánh giá liên tục sau khi xảy ra cảnh báo, thay vì dừng cách tryCatch thực hiện.