How to start tdding with ruby and wrong? - ruby

I know how to do TDD in other languages, but I'm new to both ruby and wrong. I'm struggling a bit with the fundamentals of how to setup a (toy) project. I want to write a method which computes the factorial (n! = 1 * 2 * 3 * ... * n). I have created the file test/factorial_test.rb, which so far contains
require 'wrong'
include Wrong
How do I proceed from here? Do I write my assertions in the global scope of the file
assert { factorial(1) == 1 }
assert { factorial(2) == 2 }
#...
(which feels a bit weird)? Or should I follow some (which?) convention and wrap each test in its own method
def one_factorial_should_be_one
assert { factorial(1) == 1 }
end
I'm a bit lost with the fundamentals here, so any answer on what is considered best-practice here is highly appreciated.

Wrong merely provides a couple (admittedly smart) assertion methods. You still need a framework to automate running the tests, e.g. minitest.

You can start with minitest testing framework that included with standard library. it is more productive and simple then using assert directly.

There are several testing frameworks available in Ruby
Test::Unit
minitest
rspec
shoulda - similar to rspec
cucumber - a BDD testing framework
The basic Ruby testing framework is Test::Unit. A simple example looks as follows:
require 'test/unit'
class MyTest < Test::Unit::TestCase
def test_equality
assert_equal(1,1)
end
end
Recently Minitest was incorporated into Ruby standard library, so if you wish to use this library you don't have to install anything. A simple minitest spec looks as follows:
require 'minitest/autorun'
describe Factorial do
it "should provide factorial of 1 as 1" do
factorial(1).must_equal 1
end
end

Related

Ruby Monk - Understanding Inheritance - Alternate solution not accepted?

I have been coding for three or four months (started in Python) and I am just getting into Ruby on account of Rails popularity.
To help build my understanding of the Ruby language, I have been going through the problems on Ruby Monk. The Ruby Primer: Ascent 1.1 - Understanding Inheritance course has the following problem:
Write a method that takes a class and a subclass as arguments and returns a boolean regarding whether or not the subclass is an ancestor of the class.
Here is what I came up with (note: Ruby Monk decided to go with spelling "klass" for "class"):
def is_ancestor?(klass, subclass)
subclass.ancestors.map{ |ancestor| ancestor.to_s }.include? klass.to_s
end
This code passes all tests except for a special one that states doesn't use any other methods to solve the problem (yes, there's a shortcut :)).
I was really vexed as to how to solve this without using other methods, and so I looked at the proposed solution. Here is what Ruby Monk says that answer should be.
def is_ancestor?(klass, subclass)
current_class = subclass
while !current_class.superclass.nil? && current_class != klass
current_class = current_class.superclass
end
current_class == klass
end
I understand this code. What I don't understand is why this code passes the test requirement of not using methods while my code doesn't. After all, the Ruby Monk proposed answer does use methods (see !current_class.superclass.nil).
Am I missing something here? Perhaps I don't really understand what a method is. Perhaps my code does work and is only failing because Ruby Monk is performing tests that match code 1:1.
Maybe they don't want you to use map and include? since they are not methods of classes. They are methods of arrays.
I guess this shall pass the tests.
def is_ancestor?(klass, subclass)
subclass <= klass
end
Well, strictly speaking, <= is also a method.
BTW, if you can compare classes directly, don't compare their names. You original code can be optimized as
def is_ancestor?(klass, subclass)
subclass.ancestors.include? klass
end

Basic introduction to Ruby Minitest

I am using minitest for the first time and I am having trouble understanding how to write my first test method. Can anyone assist in helping me understand what I should be testing in the below Player method get_name?
class Player
def get_name(player)
puts `clear`
center("#{player}, whats your name bro/ladybro?")
#name = gets.chomp
until #name =~ /\A[[:alnum:]]+\z/
center("you can do a combination of alphanumeric characters")
#name = gets.chomp
end
end
end
This is what I have in my test file, I was thinking I am just suppose to test the regex to make sure it takes alpha and numeric characters.
class TestPlayer < Minitest::Test
def test_get_name
describe "get_name" do
it "should allow an input of alphanumeric characters" do
assert_match(/\A[[:alnum:]]+\z/, "test_string123")
end
end
end
end
but when I run the tests, nothing seems to happen, I would imagine I am suppose to have 1 assertion.
Run options: --seed 10135
# Running:
.
Finished in 0.001565s, 638.9776 runs/s, 0.0000 assertions/s.
1 runs, 0 assertions, 0 failures, 0 errors, 0 skips
can anyone assist in demonstrating how I should write a test for this scenario? thanks.
Minitest test may be described as follows (Assertion syntax):
Its just a simple Ruby file which has a class thats typically a subclass of Minitest::Test.
The method setup will be called at the first; you can define objects that you may require in every test. Eg: Consider assigning an instance of the Player object here in an instance variable in setup method so that you can use it elsewhere in the test class.
A test is defined inside a method that starts with the string: test_; any other method can be used to reduce duplication of code but it won't be considered part of tests.
Typically you should think about testing the return value of a method you want to test.
Testing a method with external input is more convoluted, I would suggest to start with testing methods that have testable output.

Ruby: Minitest/spec and BDD Gherkin

It seems that I cannot find much documentation on Minitest/spec so I was wondering if somebody could help me figure out how to do what I need to do. Basically I want to run tests on all my classes and modules to make sure they 1.) Output the right value type if static or 2.) In the case of to_symbols all keys are symbols. Here is what I tried so far:
What I assume the Gherkin would look like:
Given binns
When the version method is called
then the return should be a float
and version should be a method or constant
What I assumed it would be with minitest/spec:
require 'minitest/autorun'
require 'minitest/spec'
require 'binns'
given Binns do
when "the version method is called" do
then "the return should be a float" do
# Do work
end
end
end
But I get:
syntax error, unexpected keyword_when (SyntaxError)
when "the version method is called" do
^
Note: I am also open to other suggestions for testing (I don't know much about cucumber and heard it was hefty) or if somebody has a book suggestion, please do tell I've been looking for a good book on Ruby Unit Testing.
MiniTest/Spec uses Rspec-style syntax: desc, it, before, after...
require 'minitest/autorun'
require 'minitest/spec'
require 'binns'
desc Binns do
it "should return a float when the version method is called" do
# Do work
end
end
If it'd make the transition easier for you, you could alias the "desc" method to "given" and "it" method to "when".
Good tutorial from Peter Cooper here.

Generating many almost identical ruby unit tests

I have a number of ruby files (a.rb, b.rb, c.rb) which define very similar classes. (They should test the same)
I've written a unit test to test these subclasses and I've generated contexts for each of the classes programatically (see below) — should I instead programatically create entire Test Classes instead? If so why and how?
I'm using the shoulda unit test extensions so my files look something like this:
a.rb
class ItsA
def number
1123
end
end
b.rb
class ItsB
def number
6784
end
end
test_letters.rb
require 'rubygems'
require 'test/unit'
require 'shoulda'
class LettersTest < Test::Unit::TestCase
Dir.glob('letters/*.rb') do |letter|
context "The #{letter} letter file"
setup do
# Here I require the ruby file and allocate
# #theclass to be an instance of the class in the file.
# I'm actually testing JavaScript using Harmony, but
# putting those details in might complicate my question.
end
should "return a number" do
assert #theclass.number.is_a? Number
end
end
end
This does the job reasonably well, but should I do some other jiggerypokery and create LetterATest, LetterBTest etc. automatically instead? If so, how would you go about doing it and why?
This really depends on how similar your classes are, but assuming they're pretty much identical and require a few small tests, and you're using shoulda, you could do something like:
class LettersTest < Test::Unit::TestCase
context "The letter classes"
setup do
#instances = # your code to get a list of the instances
end
should "return a number" do
#instances.each do |instance|
assert instance.number.is_a?(Number), "#{instance.class}.number should be a number"
end
end
end
end
In our codebase we've found that a large number of auto-generated contexts and tests leads to pretty slow test execution, so we favor the approach above to minimize the number of contexts/tests. You may not have this issue.

Why don't modules always honor 'require' in ruby?

(sorry I should have been clearer with the code the first time I posted this. Hope this makes sense)
File "size_specification.rb"
class SizeSpecification
def fits?
end
end
File "some_module.rb"
require 'size_specification'
module SomeModule
def self.sizes
YAML.load_file(File.dirname(__FILE__) + '/size_specification_data.yml')
end
end
File "size_specification_data.yml
---
- !ruby/object:SizeSpecification
height: 250
width: 300
Then when I call
SomeModule.sizes.first.fits?
I get an exception because "sizes" are Object's not SizeSpecification's so they don't have a "fits" function.
Are your settings and ruby installation ok? I created those 3 files and wrote what follows in "test.rb"
require 'yaml'
require "some_module"
SomeModule.sizes.first.fits?
Then I ran it.
$ ruby --version
ruby 1.8.6 (2008-06-20 patchlevel 230) [i486-linux]
$ ruby -w test.rb
$
No errors!
On second reading I'm a little confused, you seem to want to mix the class into module, which is porbably not so advisable. Also is the YAML supposed to load an array of the SizeSpecifications?
It appears to be that you're not mixing the Module into your class. If I run the test in irb then the require throws a LoadError. So I assume you've put two files together, if not dump it.
Normally you'd write the functionality in the module, then mix that into the class. so you may modify your code like this:
class SizeSpecification
include SomeModule
def fits?
end
end
Which will allow you to then say:
SizeSpecification::SomeModule.sizes
I think you should also be able to say:
SizeSpecification.sizes
However that requires you to take the self off the prefix of the sizes method definition.
Does that help?
The question code got me a little confused.
In general with Ruby, if that happens it's a good sign that I am trying to do things the wrong way.
It might be better to ask a question related to your actual intended outcome, rather than the specifics of a particular 'attack' on your problem. They we can say 'nonono, don't do that, do THIS' or 'ahhhhh, now I understand what you wanna do'

Resources