Skip to content
This repository has been archived by the owner on Apr 29, 2021. It is now read-only.

run more than one command inside run #168

Open
bcv opened this issue May 19, 2016 · 2 comments
Open

run more than one command inside run #168

bcv opened this issue May 19, 2016 · 2 comments

Comments

@bcv
Copy link

bcv commented May 19, 2016

Hi,

This might be a silly question but in my case I have a persistent variable in a function and so
want to call this function twice

run (func1 arg1 ; func2 arg2 )

doesnt seem to be welcomed by BATS

@ZoomyCat
Copy link

Creating a front end script for the function that runs both functions would solve this.

@ztombol
Copy link

ztombol commented May 21, 2016

@bcv Please use markdown's formatting abilities, especially code blocks, to improve readability of your posts.


Functions depending on side-effects

If all you want to do is test a function that relies on side-effects of others, simply call the functions causing the side-effects first and then run the command you want to test.

#!/usr/bin/env bats

increment_var() {
  (( ++VAR ))
}

print_var() {
  echo "$VAR"
}

@test 'Testing function that depends on side-effects' {
  increment_var   # VAR = 1
  increment_var   # VAR = 2
  run print_var
  [ "$output" == '2' ]
}

run uses command substitution to execute its arguments in a subshell. Variables set before the subshell, i.e. before run, are visible inside the subshell, i.e. to the command passed to run. On the other hand, any variable set inside a subshell will not persist when it returns.

Passing more than one command to run

If you really need to run more than one command, you can either wrap them in a function (or script as @edge226 suggested), or use bash -c.

Wrapper functions

Wrapping your functions in an extra function is a simple way of run-ing multiple functions at once.

#!/usr/bin/env bats

func_1() { echo '1'; }
func_2() { echo '2'; }

wrapper() {
  func_1
  func_2
}

@test "Passing more than one commands to \`run' with a wrapper function" {
  run wrapper
  [ "$status" -eq 0 ]        # return value of last function, i.e. `func_2'
  [ "$output" == $'1\n2' ]   # output of all functions
}

bash -c

Another solution is to run the commands in a new shell using bash -c. As far as I know this was first proposed by @inthecloud247 to solve the problem of run-ing commands that needs to pipe.

The disadvantage, or advantage depending on what you want, is that the commands are run in a new process and are thus isolated from the environment of the test case.

#!/usr/bin/env bats

@test "Passing more than one commands to \`run' with a wrapper function" {
  run bash -c 'echo 1; echo 2'
  [ "$status" -eq 0 ]        # return value of last command, i.e. `echo 2'
  [ "$output" == $'1\n2' ]   # output of all commands
}

Use the source

I encourage everybody to look into Bats' source when something is not clear. Yes, I know. User experience sucks if you need to read the source in order to use the program. Normally this is true, however a Bats test file is effectively a Bash script, which makes it very powerful. Bash is a simple scripting language with simple scoping rules and many quirks. Knowing a tiny bit about the insides of Bats is unavoidable to unlock its full potential.

With only about 900 lines Bats is very simple and lean, which I consider its biggest strength. You literally don't need to understand everything. For example printing the stack trace is not something you need to care about. Just having a rough overview of how Bats and some user facing functions, e.g. run and load, work is enough. The wiki has some helpful information on this too.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants