The previous part introduced a technique for testing client-side code from Ruby.
This part presents more tests and ends with some benchmarks.
The tests so far cover the sorting as a black box. They call the bubbleSort
method with different test cases and check that the results equal the expected values.
The tests do not check if the sorting follows the bubble sort algorithm. Obviously, code using the bubbleSort
method does not care about the internals as long as the produced array is sorted. However, as the example site shows how the sorting takes place, testing all the swaps is necessary. Another reason, even more important, is to check that the callback mechanism does work.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
def test_an_empty_array_performs_no_swap actual = @context.exec <<-JS swaps = []; bubbleSort([], function(i,j) { swaps.push([i, j]); }); return swaps; JS assert_equal [], actual end |
$> $HOME/.rvm/wrappers/ruby-2.2.0@execjs/ruby test_bubble_sort.rb Loaded suite /tmp/release/test_javascript_from_ruby/test_bubble_sort Started ...... Finished in 0.012312902 seconds. 6 tests, 6 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications 100% passed 487.29 tests/s, 487.29 assertions/s
The test executes Javascript code that passes an anonymous callback function (lines 6-8). The callback method stores in an array named swaps
all the swaps. The strange part is the return
statement on line 10 that enables to retrieve the result in the Ruby world.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
def test_a_sorted_array_performs_no_swap actual = @context.exec <<-JS swaps = []; bubbleSort([2,11,17,19], function(i,j) { swaps.push([i, j]); }); return swaps; JS assert_equal [], actual end |
$> $HOME/.rvm/wrappers/ruby-2.2.0@execjs/ruby test_bubble_sort.rb Loaded suite /tmp/release/test_javascript_from_ruby/test_bubble_sort Started ....... Finished in 0.011758991 seconds. 7 tests, 7 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications 100% passed 595.29 tests/s, 595.29 assertions/s
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
def test_sorting_waps actual = @context.exec <<-JS swaps = []; bubbleSort([11,17,1,19], function(i,j) { swaps.push([i, j]); }); return swaps; JS assert_equal [[1,2],[0,1]], actual end |
$> $HOME/.rvm/wrappers/ruby-2.2.0@execjs/ruby test_bubble_sort.rb Loaded suite /tmp/release/test_javascript_from_ruby/test_bubble_sort Started ........ Finished in 0.013542534 seconds. 8 tests, 8 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications 100% passed 590.73 tests/s, 590.73 assertions/s
The technique presented here requires to run a full Javascript interpreter. Such a thing can slow the calling code and therefore the tests.
A comparison of two different runtime layers show that choosing the runtime is important.
Running the above tests with Node.js (V8) produced next results:
$ ruby test_bubble_sort.rb Loaded suite /tmp/release/test_javascript_from_ruby/test_bubble_sort Started ........ Finished in 1.860497025 seconds. 8 tests, 8 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications 100% passed 4.30 tests/s, 4.30 assertions/s
While running the same tests with therubyracer (V8) produced next results:
$ruby test_bubble_sort.rb Loaded suite /tmp/release/test_javascript_from_ruby/test_bubble_sort Started ........ Finished in 0.013115584 seconds. 8 tests, 8 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications 100% passed 609.96 tests/s, 609.96 assertions/s
The difference is big! The second implementation is about 140 times faster… and as the report says, you could execute 600 tests per second while using the call to Node.js can only execute 4.3 tests per second.
Notice it does not mean that Node.js is slow, part of the reason is due to the fact that execjs
delegates the execution to the runtime by launching an external command.
The Ruby runtime was
$> $HOME/.rvm/wrappers/ruby-2.2.0@execjs/ruby -v ruby 2.2.0p0 (2014-12-25 revision 49005) [x86_64-linux]
The important thing is once again that structuring the code is very important because breaking it into several files has many advantages:
The tests do not require complex configurations neither a dedicated system.