简体   繁体   English

R:如何使用testthat测试依赖外部程序的函数?

[英]R: How to test a function that relies on an external program using testthat?

I have a function bowtieIndex(bowtieBuildLocation, filename) that calls bowtie2-build. 我有一个函数bowtieIndex(bowtieBuildLocation, filename) ,它调用bowtie2-build。 It's parameters are the bowtie2-build location on my system and the output filename. 它的参数是我系统上的bowtie2-build位置和输出文件名。

How do I write a test for this function without hard-coding the bowtie2-build location? 如何在不对bowtie2-build位置进行硬编码的情况下为此函数编写测试?

If all you are doing inside the function is calling an external program, then you can't test if that works directly. 如果您在函数内部所做的只是调用外部程序,那么您无法测试它是否直接起作用。 Without the code itself, this is hard to answer specifically, but if, for example, bowtieIndex is calling system to run an external program, you can mock what system will do, pretending that it worked, or failed. 没有代码本身,这很难具体回答,但是,例如,如果bowtieIndex正在调用system来运行外部程序,那么你可以模拟system将要做什么,假装它工作或失败。 Look at the documentation for testthat::with_mock . 查看testthat::with_mock的文档。

Three examples follow. 以下是三个例子。 The first parameter is the new code that will be executed instead of the real system function. 第一个参数是将执行的新代码而不是实际system函数。 The parameters that the system function was called with are available as normal in a function definition, if you want to do very specific things. 如果要执行非常具体的操作,则在函数定义可以正常使用调用system函数的参数。 I find it easier to test repeatedly rather than write a complex replacement function. 我发现重复测试更容易,而不是编写复杂的替换函数。 Everything inside the second parameter, a code block { }, is executed with a context that see only the replacement system function, including all nested function calls. 第二个参数(代码块{})内的所有内容都是使用仅查看替换系统函数的上下文执行的,包括所有嵌套函数调用。 After this code block, the with_mock function exits and the real base::system is back in scope automatically. 在此代码块之后, with_mock函数退出,并且real base::system自动返回范围。 There are some limits to what functions can be mocked, but a surprising number of base functions can be over-ridden. 可以模拟哪些函数有一些限制,但可以覆盖令人惊讶的基本函数。

# Pretend that the system call exited with a specific error
with_mock(
    `base::system`= function(...) {
        stop("It didn't work");
    }, {
    expect_error( bowtieIndex( bowtieBuildLocation, filename ),
                  "It didn't work"
    )
})

# Pretend that the system call exited with a specific return value
with_mock(
    `base::system`= function(...) {
        return(127);
    }, {
    expect_error( bowtieIndex( bowtieBuildLocation, filename ),
                  "Error from your function on bad return value." )
    expect_false( file.exists( "someNotGeneratedFile" ))
})

# Pretend that the system call worked in a specific way
with_mock(
    `base::system`= function(...) {
        file.create("someGeneratedFile")
        return(0);
    }, {
    # No error
    expect_error( got <- bowtieIndex(bowtieBuildLocation, filename), NA )

    # File was created
    expect_true( file.exists( "someGeneratedFile" ))
})

# got variable holding results is actually available here, outside
# with_mock, so don't need to test everything within the function.
test_equal( got, c( "I", "was", "returned" ))

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM