Feeds:
Posts
Comments

Posts Tagged ‘irb’


I quite recently started unit testing and as a first stop I played a bit with Ruby and Unit::Test as those are so easy to get going with. In C# you have to download nUnit and configure that, set up a lot of projects and references. Now, I’m not saying that is hard – I’m just saying that it’s easier and quicker to do it in Ruby.

The other motivation was that I decided I will start Ruby with Test Driven Development so I get into it at the get go.

So, lets get started with a few details about my environment:

  • Ruby 1.9.2
  • Windows 7

Right, lets kick this off by making a prime number calculator. We’ll start with creating both the application and the test files and create the classes.

class PrimeCalc
end

And the testfile

require_relative "../lib/prime_calc.rb"
require "test/unit"

class TestPrimeCalc < Test::Unit::TestCase
end

Nothing too wierd here. In the testfile I require the application file and the test::unit-framework.

So, true to the doctrins of TDD a test is the first starting point.
I want my prime calculator to be able to determine if a number is a prime number or not. An appropriate name would be is_prime? I think.

The test will check to see if 2 is prime.

require_relative "../lib/prime_calc.rb"
require "test/unit"

class TestPrimeCalc < Test::Unit::TestCase
  def test_2_inserted_return_true
    prime_generator = PrimeCalc.new
    actual = prime_generator.is_prime?(2)
    assert_equal(true, actual)
  end
end

And the source code only defines the function (so there’s no runtime error on missing method).

class PrimeCalc
  def is_prime?(num)
  end
end

The test fails and the “Red”-phase in TDD is reached.
See test result below:

F:\temp\> ruby test\test_prime_calc.rb
Loaded suite test/test_prime_calc
Started
F
Finished in 0.003500 seconds.

  1) Failure:
test_2_inserted_return_true(TestPrimeCalc) [test/test_prime_calc.rb:9]:
<true> expected but was
<nil>.

1 tests, 1 assertions, 1 failures, 0 errors, 0 skips

Test run options: --seed 32146

As we can see it expects true to be returned but it gets nil back (if you don’t know why this is; look up return values on methods in Ruby).

So now it’s time for the “green”-phase of TDD. Making the test pass with as little effort as possible. In this case I just let the class return true if 2 is provided, thus.

class PrimeCalc
  def is_prime?(num)
    return true if num == 2
  end
end

And the test passes. Nothing to refactor so let’s go on.

A note is probably in order here: This seems very silly. If 2 is provided then true is returned. Minimum effort to pass the test. Let’s think about this again. Why do more work than needed. If I start doing a whole lot of cases then it’s very easy to introduce bugs or do things that will never be used and just create noise. Alright, onward!

To add some flesh to the actual prime algorith I add a few more test cases. They look exactly the same as the one where 2 was sent in but this time I send in 7.

So, prime theory says that a number is only prime if it can be divided by 1 and itself and no other numbers. From this we can draw the conclusion that any multiple of 2 will never be prime.

First the red-phase. Run the tests and there will be one passing (2) and one failing (7).

Time to fix the failing test. Remember: minimum effort to go to green. In this case I will use the fact that no even numbers can be prime.

class PrimeCalc
  def is_prime?(num)
    return true if num % 2 != 0
  end
end

And run tests again.
One passing and one failing. But, this is wrong. The first test failed, 2 is prime but the method returns false. Not to worry, this one of the benefits of unit testing. Code can be changed and verification is quickly recieved. Here I say that no even numbers can be prime but 2 is even and prime. Let’s change and make sure that 2 returns true.

class PrimeCalc
  def is_prime?(num)
    return true if num == 2
    return true if num % 2 != 0
  end
end

Run unit tests and feel the excitement of all tests passing. However, let’s not rest on our laurels. There’s a lot of cases that aren’t checked. Besides, not all odd numbers are primes. Another test where 13 is used as input. Run tests and have the new test fail. Change the code to pass that test.

Here I do some optimization by not counting higher than the square root of the number itself. Prime theory says that if a factor hasn’t been found before the square root of the number is reached, then no factor will be found (apart from the number itself). Require mathn to get the sqrt method. 2 is already checked so start at 3 and start dividing the number, if a factor is found then the number isn’t prime. If no factor has been found when the loop ends then return true.

class PrimeCalc
  def is_prime?(num)
    return true if num == 2
    return true if num % 2 != 0

    i = 3
    for i in 3..Math.sqrt(num).ceil
      return false if num % i == 0
    end
 
  return true

  end
end

Run tests and see them pass. Nothing to refactor here. Or is there? Let’s take a look at the test code again.

class TestPrimeCalc < Test::Unit::TestCase

  def test_2_inserted_return_true
    prime_generator = PrimeCalc.new
    actual = prime_generator.is_prime?(2)
    assert_equal(true, actual)
  end
  
  def test_7_inserted_return_true
    prime_generator = PrimeCalc.new
    actual = prime_generator.is_prime?(7)
    assert_equal(true, actual)
  end
  
  def test_13_inserted_return_true
    prime_generator = PrimeCalc.new
    actual = prime_generator.is_prime?(13)
    assert_equal(true, actual)
  end

end

See how the line prime_generator = PrimeCalc.new is repeated in all tests? This does not follow the DRY-principle (Don’t repeat yourself). Let’s refactor that using the test frameword method setup and move the offending line in there. Setup is a method that is run before each test.

def setup
    prime_generator = PrimeCalc.new
end

Now we have a prime calculator that can return (with a decent certainty) an answer if a number is prime or not. Are we done? No, not yet. But the post is already long enough so I’ll continue in part 2.

Read Full Post »


There’s no neat and nice way of clearing the irb console as it seems.

There is a way however.

Put the following in a file called utilities.rb.

module Utilities
  def cls
    system 'cls'
  end
end

Then put the following lines into the project where you want to clear the irb console.

require_relative 'utilities.rb'

include Utilities

and use the cls function thus

Utilities.cls

Note: This only works on Windows machines.

Read Full Post »