KO!

This is KDD –Kickass Driven Development!

Knockout is a Ruby test framework that reads like a developer thinks. More specifically, KO! is a test system created to breakdown the systems analysis process into clear and obvious divisions. KO “specifications” are divided-up into cases, contexts, concerns, tests.

KO! was inspired in part by the void left behind by the discontinuation of Shoulda as a test framework. It seemed like an opportune time to implement an elegant and light-weight test framework to serve as an alternative to the monolithic RSpec.

SYNOPSIS

Writing Kick-Ass Tests

KO! tests, or specifications if you prefer, are … well, here’s an example.

KO.case "String Indexing" do

  before do
    @string = "Hello World"
  end

  test "index by substring" do |substring, index|
    @string.index(substring) == index
  end

  ok 'H' , 0
  ok 'l' , 2
  ok 'ld', 9

  test "index by regular expression" do |regular_expression, index|
    @string.index(regular_expression, index)
  end

  ok /H/  , 0
  ok /l/  , 2
  ok /o\ /, 4

end

It should be pretty clear how this plays out just by looking at it. When KO runs a test case it runs each test, which consists of trying each ok assertion. These are run through the test procedure, if the result of which evaluates as true then the test passes.

KO! handles assertions in a rather unique way. As shown, only truth of the test can be asserted. But since equality (==) is by far the most common means of test validation, KO! offers an alternative notation for specifying the `ok` expectation using `=>`. For example, the above example can also be written as follows.

KO.case "String Indexing" do

  before do
    @string = "Hello World"
  end

  test "index by substring" do |substring|
    @string.index(substring)
  end

  ok 'H'  => 0
  ok 'l'  => 2
  ok 'ld' => 9

  test "index by regular expression" do |regular_expression|
    @string.index(regular_expression)
  end

  ok /H/   => 0
  ok /l/   => 2
  ok /o\ / => 4

end

Taking this one step further the validation routine can be overridden as well. Consider the next example.

KO.case "Calculator Addition" do

  before :all do
    require 'calculator'
    @calculator = Calculator.new
  end

  test "a Calculator can add two numbers" do |input1, input2|
    @calculator.push input1
    @calculator.push input2
    @calculator.add
    @calculator
  end

  valid do |calculator, expect|
    @calculator.output == expect
  end

  ok [2, 2] => 4
  ok [2, 1] => 3
  ok [2, 0] => 2

end

Reusable Contexts

KO! has a nice feature for creating reusable contexts. They can be defined outside of any testcase and then called upon by their description for use in any testcase.

KO.context "String Instance" do

  before :all do
    @string = "Hello World"
  end

end

KO.case "String Indexing" do

  use "String Instance"

  test "index by substring" do |substring|
    @string.index(substring)
  end

  ...

Get it? You create a reusable contexts –they can load libraries, build out mocks, setup fixtures, etc. Then use use to use them in your testcases.

Of course, generally you won’t define the contexts in the same file with the testcase. You will put those in separate files in a context directory where all your tests have access to them.

Running Tests

Running KO! scripts is like this.

$ ko -Ilib path/to/tests/*.rb

LICENSE

Copyright © 2010 Thomas Sawyer

Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except in compliance with the License. You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.