I'm very glad CLIF is helping you to succeed. Thanks for expressing your appreciation! I like your idea to call out to non-Perl code within your commands. One could imagine building a custom menu-driven app based on a collection of independent tools.
CLIF is designed to handle error conditions using exceptions. If an error condition occurs during a command's execution, the command should throw an exception (even if only a die). CLIF displays error messages based on that exception.
I recommend using exception handling over error codes -- it will lead to much cleaner and more reliable code. If your tests need to take different actions based on what kind of error occurred, you can use Exception::Class to define an exception object hierarchy. Your commands can throw the proper exception based on what happens. Your test code can check the type of the exception (check out Exception::Class::TryCatch for a nice interface for catching exceptions) and act accordingly.
In order to make this work properly, you should do the following:
1. Create an exception hierarchy in a package such as "My::Custom::Exceptions" and make sure it uses CLI::Framework::Exceptions. Define new exceptions based on your error conditions. These are the exceptions that may be raised by your running commands. Each of these custom exceptions should inherit from CLI::Framework::Exception::CmdRunException.
2. In the run() method for your commands, instead of trying to return error codes, throw exceptions of the types you've defined.
3. In your application, define handle_exception to rethrow the exception (i.e. just die) instead of rendering it. For your test code, you might force that to happen with some symbol table manipulation (should be acceptable for a test script). Of course, you generally might want to handle exceptions more gracefully.
4. In your calling code (test code in your case), catch the exceptions and take the appropriate actions.
As I typed this, I realized that the need to have custom command exceptions inherit from CLI::Framework::Exception::CmdRunException is not documented. I'm adding that to my list for the next release.
And now, to switch from abstract mode to concrete mode, here's some demo code:
This is the package defining your custom exceptions: