Reputation: 3819
I have a shell script which executes a various of commands like killing processes, copying files via scp, performing remote commands via ssh and etc...
The problem is that this script is hard to maintain and hard to unit test. Moreover, I want in the future to change it so it would work with xml config file, and I think that it cant be easily done with shell scripts. So, I want to transform it to a java application, but just running many commands with ProcessBuilder doesn't feel right.
On the other hand, searching for java solutions for each "problem" that today is easily solved in shell commands (like java ssh client, java API for linux processes and etc..), also doesn't feel right.
EDIT: I know for sure that my program will run in a linux environment, so cross platform is a non-issue here.
Any suggestion?
Upvotes: 0
Views: 280
Reputation: 48864
One slightly harebrained idea for "unit testing" shell scripts would be to have a wrapper script which executes your script in a controlled environment - namely that it defines functions which "mock" the real commands you don't want to execute (e.g. ssh() { }
).
This would allow you to test the interactions you're interested in, without worrying about the other processes you're calling out to, as brainzzy describes. This is still very dependent on well designed bash code, but at least in theory it'd be possible, I think.
Demo:
$ cat /tmp/grep.sh
#!/bin/bash
# Simple program that relies on grep
echo -e "This is a test\nThis line doesn't match." | grep test
Unit Tester:
$ cat /tmp/unittest.sh
#!/bin/bash
grep() {
echo "Mock GREP result"
}
. "$@"
Now if we run grep.sh
directly, it searches as expected:
$ /tmp/grep.sh
This is a test
But if run from within the unittest script the grep
is mocked by the function:
$ /tmp/unittest.sh /tmp/grep.sh
Mock GREP result
Allowing us to test whatever behavior we're trying to verify.
This has several limiting factors, like needing to be run from the same shell (the .
command) meaning that if the script in turn calls other scripts, they will again be calling the real commands.
An alternative would be to define a set of scripts in a unit test directory, e.g.
$ ls /usr/local/unitbin
grep
ssh
svn
Then have the unit test script change the PATH the script runs from, e.g.:
$ cat /tmp/unittest.sh
#!/bin/bash
PATH=/usr/local/unitbin:$PATH "$@"
This should work for scripts that call other scripts in turn.
Both of these examples, like I said, are slightly ridiculous, and potentially more trouble than they're worth. I would definitely look to the other answers to this question before considering this path. But if you have bash code that you'd like to unit test, but can't run in a sandbox safely, one of these options might work for you.
Upvotes: 0
Reputation: 3053
I've used many languages for shell scripting; from Python, PHP, to Java - and I keep coming back to using the right tool for the job.
In the linux world, bash scripting is usually powerful enough, and perl has lots of good OS support.
It has surprised some of our developers in the past, that you can actually build functions within bash scripts, hand around state and manage a lot of what you'd normally expect. It's just another language, but with the command line at the heart of it.
UPDATE:
Another thing I'd add is follow the principle of least astonishment, which in this case means that you should write the code to be what those managing the system would expect. All too often I see Java programmers writing their deployment like Java programmers, not system administrators. If you're going to be handing these scripts over to a system administrator / operations role, then they are likely to be more familiar with shell scripts than a Java program they would have to compile.
On another note - treat your shell scripts like proper code. Put it in source control (my whole /etc is under Git management), have a bug tracking system, etc. It makes maintenance much easier.
Upvotes: 5
Reputation: 12489
To me it sounds like you need the ease of shell scripting combined with the ability to maintain and test the code while still being able to do some higher level tasks within the language.
Luckily that's exactly where the dynamic languages shine (also called scripting languages). There's (in my personal order of preference) Python, Ruby, Perl, Groovy, and a few others.
Upvotes: 1
Reputation: 803
Java isn't quite good for shell scripting, but Groovy (which is based on Java), might be better to write and mantain, and is fully compatible with Java
http://groovy.codehaus.org/Running
Upvotes: 1