Skip to content

Function Testing

nf-test allows testing of functions that are defined in a Nextflow file or defined in lib. Please checkout the CLI to generate a function test.

Syntax

nextflow_function {

    name "<NAME>"
    script "<PATH/TO/NEXTFLOW_SCRIPT.nf>"
    function "<FUNCTION_NAME>"

    test("<TEST_NAME>") {

    }
}

💡 Script paths that start with ./ or ../ are considered relative paths. These paths are resolved based on the location of the test script. Relative paths are beneficial when you want to reference files or directories located within the same directory as your test script or in a parent directory. These paths provide a convenient way to access files without specifying the entire path.

Multiple Functions

If a Nextflow script contains multiple functions and you want to test them all in the same testsuite, you can override the function property in each test. For example:

functions.nf

def function1() {
  ...
}

def function2() {
  ...
}

functions.nf.test

nextflow_function {

    name "Test functions"
    script "functions.nf"

    test("Test function1") {
      function "function1"
      ...
    }

    test("Test function2") {
      function "function2"
      ...
    }
}

Functions in lib folder

If you want to test a function that is inside a groovy file in your lib folder, you can ignore the script property, because Nextflow adds them automatically to the classpath. For example:

lib\Utils.groovy

class Utils {

    public static void sayHello(name) {
        if (name == null) {
            error('Cannot greet a null person')
        }

        def greeting = "Hello ${name}"

        println(greeting)
    }

}

tests\lib\Utils.groovy.test

nextflow_function {

    name "Test Utils.groovy"

    test("Test function1") {
      function "Utils.sayHello"
      ...
    }
}

Note: the generate function command works only with Nextflow functions.

Assertions

The function object can be used in asserts to check its status, result value or error messages.

// function status
assert function.success
assert function.failed

// return value
assert function.result == 27

//returns a list containing all lines from stdout
assert function.stdout.contains("Hello World") == 3

Example

Nextflow script

Create a new file and name it functions.nf.

def say_hello(name) {
    if (name == null) {
        error('Cannot greet a null person')
    }

    def greeting = "Hello ${name}"

    println(greeting)
    return greeting
}

nf-test script

Create a new file and name it functions.nf.test.

nextflow_function {

  name "Test Function Say Hello"

  script "functions.nf"
  function "say_hello"

  test("Passing case") {

    when {
      function {
        """
        input[0] = "aaron"
        """
      }
    }

    then {
      assert function.success
      assert function.result == "Hello aaron"
      assert function.stdout.contains("Hello aaron")
      assert function.stderr.isEmpty()
    }

  }

  test("Failure Case") {

    when {
      function {
        """
        input[0] = null
        """
      }
    }

    then {
      assert function.failed
      //It seems to me that error(..) writes message to stdout
      assert function.stdout.contains("Cannot greet a null person")
    }
  }
}

Execute test

nf-test test functions.nf.test