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.
-
Cases delineate the overall requirement that is to be demonstrated.
-
Contexts provide reusable procedures to setup and teardown test fixtures.
-
Concerns break-up test cases into separate areas of concern, i.e. sub-cases.
-
Tests compose the proof of a testcase as a set of assertions.
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.