Question

I am doing iOS testing using Frank. It is a ruby gem that uses Cucumber as well. I have a "Given" step that checks whether the app is running or if it has crashed. If my step finds that it has crashed I would like to launch the app again. I launch the app using a shell script which is stored somewhere near the cucumber .feature files.

How can I call a script from that step definition?

Was it helpful?

Solution

You can do this a few different ways

Kernel.system "command"
%x[command]
`command`

OTHER TIPS

As other answers suggested, there are many ways of executing shell scripts from Ruby, but they're all not created equal. I'll try to explain all methods i know in more detail.

Backticks

`command arg1 arg2`
%x(command arg1 arg2)

Runs the command in a subshell and returns the output of the command. The command and its arguments are provided as a string delimited by backticks. An alternative syntax is %x(...) which serves to avoid escaping issues, e.g. when you want to execute a command that contains backticks itself. The parentheses can be replaced by other delimiters such as [], {}, !!, … in order to be able to work around just about any escaping issue.

Stderr is printed as normal, Stdout is suppressed. Returns the stdout output of the command. This means you can use the backtick notation to get the output of a command into a variable for further processing.

Kernel.exec

exec("command arg1 arg2")
exec("command", "arg1", "arg2")

Replaces the current process by running the command. The command and its arguments are provided as a normal string or as a comma delimited list of strings. Can be useful if you already have a list of arguments as an array. Output is left as is, i.e. will be printed to the console as if the command was run directly.

Kernel.system

system("command arg1 arg2")
system("command","arg1 arg2")

Like Kernel.exec but runs in a subshell again. Returns true if the process exited correctly (status 0), false otherwise. This works great inside if-statements.

Kernel.spawn

pid = spawn("command")
# do other stuff
Process.wait(pid)

Similar to Kernel.system but will spawn a child process to run the specified command. The parent process will thus not wait for the command to finish executing unless Process.wait is used. The return value is the PID of the spawned process.

IO.popen

io = IO.popen("command")
IO.popen("command") {|io| ... }

Runs the command in a child process again but allows for greater control over the IO. The child processes' stdout and stdin are connected to an IO object that is either accessible as the return value or a block parameter. If obtained via return value, the IO object should be closed after using it with io.close.

Open3

For use-cases more advanced than system or IO.popen, you can use Open3 from the Ruby standard library. Its popen3 method lets you manually interact with the stdin, stdout, and stderr of the child process. Open3’s popen2 method is the same except it doesn’t give you stderr. An example of using popen2:

require 'open3'

Open3.popen2("wc -c") do |stdin, stdout, status_thread|
  stdin.print "answer to life the universe and everything"
  stdin.close
  p stdout.gets #=> "42\n"
end

Here are some nice ways. Backticks are probably the least intrusive. But beware: as pointed out by tadman, exec terminates the calling process, which can be averted by creating a child process or using system.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top