I have a test file, ipca_test.rb:
require "test_helper"
require "matrix" # Does needing to include this here mean I'm doing something wrong?
class IpcaTest < Minitest::Test
def test_that_it_has_a_version_number
refute_nil ::Ipca::VERSION
end
def test_it_does_something_useful
refute false
end
def test_on_a_random_matrix
p = rand(3..10)
n = rand(20..50)
m = Matrix.build(n, p) {|_, _| rand(-10.0..10.0)}
pca = Ipca::Pca.new(m)
eigenvalue, r = pca.first_principal_component
puts "eigenvalue: #{eigenvalue}, r: #{r}"
assert eigenvalue.kind_of? Numeric
assert_equal Vector, r.class
end
end
The program I'm trying to test is ipca.rb:
require "ipca/version"
module Ipca
class Error < StandardError; end
class Pca
def initialize data
#data = data.class == Matrix ? data : Matrix.rows(data)
end
# see https://en.wikipedia.org/wiki/Principal_component_analysis#Iterative_computation
def first_principal_component(c = 100, tolerance = 0.001) # not sure whether defaults are apropos
p = #data.column_vectors.count
r = Vector.elements(Array.new(p) {|_| rand}).normalize
eigenvalue = nil
c.times do
s = Vector.zero(p)
#data.row_vectors.each do |x|
s += x.dot(r)*x
end
eigenvalue = r.dot(s) # ?
error = (eigenvalue*r-s).norm
r = s.normalize
exit if error < tolerance
end
return [eigenvalue, r]
end
end
end
(Git repo of entire tree)
Sometimes the test is successful, but much more often the test never gets to "Finished". In these cases there are zero or more dots representing (I assume) successful assertions. I'm guessing that the tests runs are being halted by some kind of timeout somewhere in my bundle, and that this times out intermittently because the input data for the test is of varying size. But if it's a timeout issue why is there not a message to that effect? Here is a series of test runs:
josie#josie-Inspiron-580:/var/www/html/ruby/ipca$ ruby -Itest
test/ipca_test.rb Run options: --seed 44059
# Running:
..josie#josie-Inspiron-580:/var/www/html/ruby/ipca$ ruby -Itest
test/ipca_test.rb Run options: --seed 57681
# Running:
.josie#josie-Inspiron-580:/var/www/html/ruby/ipca$ ruby -Itest
test/ipca_test.rb Run options: --seed 57222
# Running:
..josie#josie-Inspiron-580:/var/www/html/ruby/ipca$ ruby -Itest
test/ipca_test.rb Run options: --seed 7474
# Running:
..josie#josie-Inspiron-580:/var/www/html/ruby/ipca$ ruby -Itest
test/ipca_test.rb Run options: --seed 1938
# Running:
..josie#josie-Inspiron-580:/var/www/html/ruby/ipca$ ruby -Itest
test/ipca_test.rb Run options: --seed 61325
# Running:
..eigenvalue: 2027.687580111128, r: Vector[0.03288542301229099,
-0.09533529249551115, 0.3033273986606458, 0.07951734565050736, 0.3575555246291426, 0.41614419068773545, 0.4928822662304588, 0.28785088479078025, 0.5144766379975693] .
Finished in 0.037173s, 80.7047 runs/s, 107.6063 assertions/s.
3 runs, 4 assertions, 0 failures, 0 errors, 0 skips
josie#josie-Inspiron-580:/var/www/html/ruby/ipca$
Use break instead of exit:
break if error < tolerance
break exits just the do loop.
exit exits the program itself not giving a chance for minitest to fail the test
Related
Hi I'm completely new to Ruby. I'm trying to run Minitests, it use to work fine until I added a constructor to my CountDown class.
Here is the code:
require 'benchmark'
require 'minitest/autorun'
#! /usr/bin/env ruby
#This is our countdown class
# :reek:DuplicateMethodCall
# :reek:TooManyStatements
class CountDown
def initialize(time)
#time = time
end
def count()
wait_time = #time.to_i
print wait_time.to_s + " seconds left\n"
sleep 1
wait_time = wait_time - 1
wait_time.downto(1).each do |time_left|
sleep 1
print time_left.to_s + " seconds left\n" if (time_left % 60) == 0
end
print "\a"
end
end
#This class is responsible for our test cases
class CountDownTest < Minitest::Test
def setup
#count_down = CountDown.new(10)
end
def testing_lowerbound
time = Benchmark.measure{
#count_down.count
}
assert time.real.to_i == 10
end
end
This my my output:
teamcity[enteredTheMatrix timestamp = '2017-09-28T15:10:11.470-0700']
teamcity[testCount count = '0' timestamp = '2017-09-28T15:10:11.471-0700'] Finished in 0.00038s 0 tests, 0
assertions, 0 failures, 0 errors, 0 skips
Process finished with exit code 0
Any idea what's wrong? It looks fine to me.
Tests should start with the prefix test_ not testing_. Using the wrong prefix makes MiniTest assume they're doing something other than running a test, so it ignores them.
When I have time I like to take on a challenge at codewars.
Until now I used test/unit to do my unit testing but I would like to use Rspec now without changing my way of working. These are small methods/files/tests so I like to keep everything together in one script.
I run almost all of my code using Sublime Text and get the result in a window at the bottom of the editor.
Here my working test/unit example
require 'test/unit'
def anagrams(word, words)
words.select { |w| w.chars.sort == word.chars.sort }
end
class MyTest < Test::Unit::TestCase
def test_fail
assert_equal(['aabb', 'bbaa'], anagrams('abba', ['aabb', 'abcd', 'bbaa', 'dada']) )
assert_equal(['carer', 'racer'], anagrams('racer', ['crazer', 'carer', 'racar', 'caers', 'racer']) )
assert_equal([], anagrams('laser', ['lazing', 'lazy', 'lacer']) )
end
end
This gives in Sublime the following output
Loaded suite C:/Users/.../codewars/anagram
Started
.
Finished in 0.001 seconds.
------
1 tests, 3 assertions, 0 failures, 0 errors, 0 pendings, 0 omissions, 0 notifications
100% passed
------
1000.00 tests/s, 3000.00 assertions/s
[Finished in 0.3s]
And here what I tried for Rspec
require 'rspec'
describe "Anagrams" do
def anagrams(word, words)
words.select { |w| w.chars.sort == word.chars.sort }
end
it "should only match the anagrams" do
anagrams('abba', ['aabb', 'abcd', 'bbaa', 'dada']) == ['aabb', 'bbaa']
end
end
In Sublime text, I get no output, just a empty black window with the time it took to execute the script, if I use the console and run rspec anagram.rb I get
.
Finished in 0.001 seconds (files took 0.10601 seconds to load)
1 example, 0 failures
How do I have my code and test in the same file and do the test just by running the script in my Sublime Text editor (and get the output) and how could I better rephrase this test ?
You just need to tell the RSpec::Core::Runner to run your spec.
Adding RSpec::Core::Runner.run([$__FILE__]) at the end of your fill should work.
Updated code:
require 'rspec'
describe "Anagrams" do
def anagrams(word, words)
words.select { |w| w.chars.sort == word.chars.sort }
end
it "should only match the anagrams" do
anagrams('abba', ['aabb', 'abcd', 'bbaa', 'dada']) == ['aabb', 'bbaa']
end
end
RSpec::Core::Runner.run([$__FILE__])
I don't know what magic you used for sublime text to auto run your unit tests.
What I can answer is how to phrase the test better.
require 'rspec'
def anagrams(word, words)
words.select { |w| w.chars.sort == word.chars.sort }
end
RSpec.describe "Anagrams" do
it "matches words that are anagrams" do
# 2 different ways to do this
expect(anagrams('abba', ['aabb', 'abcd', 'bbaa', 'dada'])).to match_array(['aabb', 'bbaa'])
expect(anagrams('abba', ['aabb', 'abcd', 'bbaa', 'dada'])).to contain_exactly('aabb', 'bbaa')
end
end
match_array & contain_exactly are identical, except that match_array needs 1 parameter: array and contain exactly needs no array, instead you list all memebers of array.
https://www.relishapp.com/rspec/rspec-expectations/docs/built-in-matchers/contain-exactly-matcher
You could also break this into 2 or more specs if you want to. I'd do that if logic was more complicated. Going to do it here anyway so you can see more examples of rspec messages. Using should in spec name is no longer recommended.
RSpec.describe "Anagrams" do
it "when no annagrams found returns empty array" do
expect(anagrams('abba', ['abcd', 'dada'])).to eq([])
end
it "recognizes itself as annagram" do
expect(anagrams('abba', ['abba'])).to eq(['abba'])
end
it "returns array containing words that are anagrams" do
expect(anagrams('abba', ['aabb', 'abcd', 'bbaa', 'dada'])).to contain_exactly('aabb', 'bbaa')
end
end
I'm starting the 06_performance_monitor exercise in TestFirst Ruby and the failure it lists is in the Rspec that was provided in the materials for TestFirst Ruby tutorial (where it says undefined method 'measure'). From what I've been able to find online, it seems this tutorial was written for Rspec 2 and Ruby 1.9. I currently have Rspec 2.99.0, Ruby 1.9.3, and Rake 0.9.22 installed. I guess my question is, what am I doing wrong/do I need different versions? I don't understand why the provided Rspec doesn't seem to work as it should. This happened in one other exercise for this tutorial but it was only a minor error message that didn't interfere with my testing.
caitlyns-mbp:06_performance_monitor caitlynyu$ rake
(in /Users/caitlynyu/Desktop/learn_ruby)
Run options: include {:focus=>true}
All examples were filtered out; ignoring {:focus=>true}
Performance Monitor
runs a block N times (FAILED - 1)
Failures:
1) Performance Monitor runs a block N times
Failure/Error: measure(4) do
NoMethodError:
undefined method `measure' for #<RSpec::Core::ExampleGroup::Nested_1:0x007fcdc11b8578>
# ./06_performance_monitor/performance_monitor_spec.rb:53:in `block (2 levels) in <top (required)>'
Finished in 0.00081 seconds
1 example, 1 failure
Failed examples:
rspec ./06_performance_monitor/performance_monitor_spec.rb:51 # Performance Monitor runs a block N times
Randomized with seed 2933
/Users/caitlynyu/.rvm/rubies/ruby-1.9.3-p547/bin/ruby -S rspec /Users/caitlynyu/Desktop/learn_ruby/06_performance_monitor/performance_monitor_spec.rb -I/Users/caitlynyu/Desktop/learn_ruby/06_performance_monitor -I/Users/caitlynyu/Desktop/learn_ruby/06_performance_monitor/solution -f documentation -r ./rspec_config failed
caitlyns-mbp:06_performance_monitor caitlynyu$
UPDATE
My code below (I know it doesn't pass any of the tests below, I was just playing around with this first):
def performance_monitor
start = Time.now
yield
return "#{Time.now - start}"
end
I've never used a method called 'measure' that shows up in the Rspec which is below:
# # Topics
#
# * stubs
# * blocks
# * yield
#
# # Performance Monitor
#
# This is (a stripped down version of) an actual useful concept: a
# function that runs a block of code and then tells you how long it
# took to run.
require "performance_monitor"
require "time" # loads up the Time.parse method -- do NOT create time.rb!
describe "Performance Monitor" do
before do
#eleven_am = Time.parse("2011-1-2 11:00:00")
end
it "takes about 0 seconds to run an empty block" do
elapsed_time = measure do
end
elapsed_time.should be_within(0.1).of(0)
end
it "takes exactly 0 seconds to run an empty block (with stubs)" do
Time.stub(:now) { #eleven_am }
elapsed_time = measure do
end
elapsed_time.should == 0
end
it "takes about 1 second to run a block that sleeps for 1 second" do
elapsed_time = measure do
sleep 1
end
elapsed_time.should be_within(0.1).of(1)
end
it "takes exactly 1 second to run a block that sleeps for 1 second (with stubs)" do
fake_time = #eleven_am
Time.stub(:now) { fake_time }
elapsed_time = measure do
fake_time += 60 # adds one minute to fake_time
end
elapsed_time.should == 60
end
it "runs a block N times" do
n = 0
measure(4) do
n += 1
end
n.should == 4
end
it "returns the average time, not the total time, when running multiple times" do
run_times = [8,6,5,7]
fake_time = #eleven_am
Time.stub(:now) { fake_time }
average_time = measure(4) do
fake_time += run_times.pop
end
average_time.should == 6.5
end
it "returns the average time when running a random number of times for random lengths of time" do
fake_time = #eleven_am
Time.stub(:now) { fake_time }
number_of_times = rand(10) + 2
average_time = measure(number_of_times) do
delay = rand(10)
fake_time += delay
end
average_time.should == (fake_time - #eleven_am).to_f/number_of_times
end
end
Ruby Mongo Driver question:
How do I output 5_000 document batches from the collection at a time until I read the last document in the collection without dumping the entire database into memory first?
This is really bad method for me:
mongo = MongoClient.new('localhost', 27017)['sampledb']['samplecoll']
#whois.find.to_a....
Mongo::Collection#find returns a Mongo::Cursor that is Enumerable. For batch processing Enumerable#each_slice is your friend and well worth adding to your toolkit.
Hope that you like this.
find_each_slice_test.rb
require 'mongo'
require 'test/unit'
class FindEachSliceTest < Test::Unit::TestCase
def setup
#samplecoll = Mongo::MongoClient.new('localhost', 27017)['sampledb']['samplecoll']
#samplecoll.remove
end
def test_find_each_slice
12345.times{|i| #samplecoll.insert( { i: i } ) }
slice__max_size = 5000
#samplecoll.find.each_slice(slice__max_size) do |slice|
puts "slice.size: #{slice.size}"
assert(slice__max_size >= slice.size)
end
end
end
ruby find_each_slice_test.rb
Run options:
# Running tests:
slice.size: 5000
slice.size: 5000
slice.size: 2345
.
Finished tests in 6.979301s, 0.1433 tests/s, 0.4298 assertions/s.
1 tests, 3 assertions, 0 failures, 0 errors, 0 skips
This question sounds stupid, but I never found an answer online to do this.
Assume you have a test suite like this page:
http://en.wikibooks.org/wiki/Ruby_Programming/Unit_testing
or code:
require "simpleNumber"
require "test/unit"
class TestSimpleNumber < Test::Unit::TestCase
def test_simple
assert_equal(4, SimpleNumber.new(2).add(2) )
assert_equal(4, SimpleNumber.new(2).multiply(2) )
end
def test_typecheck
assert_raise( RuntimeError ) { SimpleNumber.new('a') }
end
def test_failure
assert_equal(3, SimpleNumber.new(2).add(2), "Adding doesn't work" )
end
end
Running the code:
>> ruby tc_simpleNumber2.rb
Loaded suite tc_simpleNumber2
Started
F..
Finished in 0.038617 seconds.
1) Failure:
test_failure(TestSimpleNumber) [tc_simpleNumber2.rb:16]:
Adding doesn't work.
<3> expected but was
<4>.
3 tests, 4 assertions, 1 failures, 0 errors
Now, how to use a variable (what kind?) to save the testing results?
e.g., an array like this:
[{:name => 'test_simple', :status => :pass},
{:name => 'test_typecheck', :status => :pass},
{:name => 'test_failure', :status => :fail},]
I am new to testing, but desperate to know the answer...
you need to execute your test script file, that's it, the result will display pass or fails.
Suppose you save file test_unit_to_rspec.rb, after that execute below command
ruby test_unit_to_rspec.rb
Solved the problem with setting a high verbose level, in a test runner call.
http://ruby-doc.org/stdlib-1.8.7/libdoc/test/unit/rdoc/Test/Unit/UI/Console/TestRunner.html
require 'test/unit'
require 'test/unit/ui/console/testrunner'
class MySuperSuite < Test::Unit::TestSuite
def self.suite
suites = self.new("My Super Test Suite")
suites << TestSimpleNumber1
suites << TestSimpleNumber2
return suites
end
end
#run the suite
# Pass an io object
#new(suite, output_level=NORMAL, io=STDOUT)
runner = Test::Unit::UI::Console::TestRunner.new(MySuperSuite, 3, io)
results will be saved in the io stream in a nice format fo each test case.
What about using '-v' (verbose):
ruby test_unit_to_rspec.rb -v
This should show you a lot more information
You can check out another of Nat's posts for a way to capture the results. The short answer to your question is that there is no variable for capturing the results. All you get is:
Loaded suite My Special Tests
Started
..
Finished in 1.000935 seconds.
2 tests, 2 assertions, 0 failures, 0 errors
Which is not very helpful if you want to report to someone else what happened. Nat's other post shows how to wrap the Test::Unit in rspec to get a better result and more flexibility.
class Test::Unit::TestCase
def setup
#id = self.class.to_s()
end
def teardown
#test_result = "pass"
if(#_result.failure_count > 0 || #_result.error_count > 0)
#test_result = "fail"
# making sure no errors/failures exist before the next test case runs.
i = 0
while(i < #_result.failures.length) do
#_result.failures.delete_at(i)
i = i + 1
end
while(i < #_result.errors.length) do
#_result.errors.delete_at(i)
i = i + 1
end
#test_result = "fail"
end # if block ended
puts"#{#id}: #{#test_result}"
end # teardown definition ended
end # class Test::Unit::TestCase ended
Example Output :
test1: Pass
test2: fail
so on....