bryton-lite

Bare bones Ruby implementation of the Bryton testing protocol

Install

The usual:

gem install bryton-lite

Overview

Bryton is a file-based testing protocol. The point of Bryton is to allow you to write your tests without constraints on how they need to be organized. All your test scripts have to do is output a JSON object as the last line of STDOUT. At a minimum, the JSON object should have a "success" element set to true or false:

{"success":true}
{"success":false}

Bryton allows you to start simple, with just a few tests scripts that you can run manually to see the results. As you progress to automated testing you can use a Bryton runner to run all your tests.

A Bryton runner (i.e. the routine running the tests) calls each executable file in a directory, collecting the results. Those executables can be written in any language, Ruby or otherwise. It also recurses into subdirectories. The runner then reports the results back to you in either a human readable or machine readable format.

Bryton (which is currently under development) will be a full featured testing system with a large array of options. Bryton::Lite only implements a few of the features. In fact, Bryton::Lite is to be used for testing Bryton.

Use

This gem has two modules, one for building tests and one for running tests. The two modules don't depend on each other. You can use one or the other or both.

Bryton::Lite::Tests

Basic example

Bryton is designed to be simple. You don't need any special tools to implement the basic protocol. For example, consider the following script:

#!/usr/bin/ruby -w
require 'json'

# some test
def some_test()
   return true
end

# results hash
results = {}

# run a test
results['success'] = some_test()

# output results
puts JSON.generate(results)

Notice that you don't even need this gem to run that script. Bryton is designed to be simple and easy to implement. That test outputs a JSON object as either {"success":true} or {"success":false}. Now let's take a look at a script in which a test fails.

#!/usr/bin/ruby -w
require 'json'

# some test
def some_test()
   return false
end

# results hash
results = {}

# run a test
if some_test()
   results['success'] = true
else
   results['errors'] ||= []
   results['errors'].push({'id'=>'some_test_failure'})
end

# output results
puts JSON.generate(results)

In this example one of the tests fails. The script could have simply set success to false, but instead it gives a little more information by creating the errors array and adding a message to it. Notice that success is never explicitly set. That's because the presence of an error implies failure.

Bryton::Lite::Tests.assert

Bryton::Lite::Tests provides several tools for building and outputting test results. Consider this script:

#!/usr/bin/ruby -w
require 'bryton/lite'

# some test
def some_test
   return false
end

# test a function
Bryton::Lite::Tests.assert some_test()

# done
Bryton::Lite::Tests.try_succeed
Bryton::Lite::Tests.done

In this test, we create a function that, in this case, always returns false. Then we use Bryton::Lite::Tests.assert to check the result of that function. If the test fails, then an error is added to the output hash.

Next we call Bryton::Lite::Tests.try_succeed. That function marks the test script as successful, but only if there are not errors. Remember that a test run is only considered successful if the output explicitly sets success as true.

Finally, we call Bryton::Lite::Tests.done, which outputs the the results and exits. Bryton::Lite::Tests.done should be called as the last line of your script.

Here's the output for that run.

{"errors":[{"line":12,"file":"./basic.rb"}]}

By default, assert notes the file name and line number of the error. You can also add an id for the error:

Bryton::Lite::Tests.assert some_test(), 'running some_test()'

which outputs

{"errors":[{"line":11,"file":"./id.rb","id":"running some_test()"}]}

If you want to manually add information to the error, use a do block. assert yields the error hash:

Bryton::Lite::Tests.assert(some_test()) do |error|
   error['notes'] = 'failure of some_test'
end

which outputs a JSON object with whatever you added:

{"errors":[{"line":12,"file":"./block.rb","notes":"failure of some_test"}]}

Bryton::Lite::Tests.fail

fail works much like assert, but it unconditionally adds an error. fail has syntax similar to assert.

Bryton::Lite::Tests.fail() do |error|
   error['notes'] = 'failed db test'
end

which outputs JSON like this:

{"errors":[{"line":6,"file":"./no-id.rb","notes":"failed db test"}]}

Bryton::Lite::Runner

Bryton::Lite::Runner runs all the tests in a directory tree. The full Bryton protocol will allow you to pick and choose which tests to run and what to do on success or failure. Bryton::Lite::Runner just implements the basic concept of running all the tests.

To run tests, your script should go to the root of the directory where you have your test files. Then just run Bryton::Lite::Runner.run.

#!/usr/bin/ruby -w
require 'bryton/lite'

Dir.chdir '../tests'
Bryton::Lite::Runner.run
puts Bryton::Lite::Runner.success?

If you just want to know the success or failure of the tests, output Bryton::Lite::Runner.success?. If you want more information, you can output all the results from the entire test run:

puts JSON.pretty_generate(Bryton::Lite::Tests.hsh)

Notice that we use Bryton::Lite::Tests.hsh to get the results. The runner stores results with Bryton::Lite::Tests because the run itself is a test. There are main three elements to a results hash.

key data type explanation
success true, false, or nil Indicates success of failure of a test. Nil is considered false.
file hash Hash of information about the fiule being tested. Should at least contain the path to the file relative to the root directory of the test. If dir is true then the file is a directory.
errors array Each element of the array give details about an error. If any elements are present in the errors array then success should not be true.
nested array Array of nested test results. Every nested result must be successful or the entire test run is considered to have failed.

As with any hash, you can add your own custom elements.

Here is a sample output from a script run. (JSON doesn't allow comments, but I've added some here for clarity.

// root directory for tests
{
   // indicates that the test run failed
   "success": false,

   // file information about this directory
   "file": {
      "path": ".",
      "dir": true
   },

   // nested list of subtests
   // directories always have an array of nested tests
   "nested": [
      {
         "file": {
            "path": "./load-tests",
            "dir": true
         },

         "nested": [
            {
               // indicates that this file test failed
               "success": false,

               // file information about ./load-tests/crash.rb
               "file": {
                  "path": "./load-tests/crash.rb"
               },

               // array of error messages
               "errors": [
                  {
                     // indicates that execution of the script failed
                     "id": "execution-failed",

                     // STDERR from the execution
                     "stderr": "./crash.rb:5:in `/': divided by 0 (ZeroDivisionError)\n\tfrom ./crash.rb:5:in `<main>'\n"
                  }
               ]
            },

            {
               // indicates that the script succeeded
               "success": true,

               // file information
               "file": {
                  "path": "./load-tests/success.rb"
               }
            }
         ]
      },

      {
         "success": true,
         "file": {
            "path": "./test-a.rb"
         }
      }
   ]
}

History

date version notes
May 22, 2023 1.0 Initial upload
May 22, 2023 1.1 Added refute, assert_equal and refute_equal