AbUndZu AbUndZu - 27 days ago 4x
Ruby Question

how to test program without running it [ruby test/unit]

I have some code like this

def something(x)
x = x * 1

puts "something"

and i want to make tests to this code

require 'something.rb'
require 'test/unit'

class StringTest < Test::Unit::TestCase
def test_something
assert_equal(1, something(1))

it works, but i have output from all instructions from file (i see "something" before tests)
how can i test only methods in my code, without running all?


When you require a file, you literally are "running it". That is how your test knows that something method is defined - because it has already initialised the definition.

What you are really asking, I suppose, is how to silence the puts command(s) when requireing the file. There are several possible approaches for this - here are some suggestions:

Don't use puts, directly. One really crude but simple approach could be to wrap these debug messages a helper method - such as:

# something.rb:

def debug(message)
  unless $debug_messages_disabled
    puts message

def something(x)
  x = x * 1

debug "something"

# in your spec (spec_helper.rb?):
$debug_messages_disabled = true

However, this approach does not scale well at all...

A better approach could be to use a Logger instead of puts. If you choose to log to a file, then your problem is already solved! And, if you insist on logging to stdout, then you could simply increase the log level when running the tests - so long as you have a convenient way to set this log level. Something like:

# something.rb:
# ...
MyApplication.logger.debug "something" # NOT `puts`

# config/environments/development.rb
config.log_level = :debug

# config/environments/test.rb
config.log_level = :warn

...But that sort of approach probably way too much effort to set up for a single-file like this!

Which leads to the final, easy option to hide the output of those puts commands: Suppress the STDOUT in your tests.

You could either achieve this by only stubbing puts commands:

# spec_helper.rb
before do
  IO.any_instance.stub(:puts) # globally
  YourClass.any_instance.stub(:puts) # or for just one class

Or, for an even more general solution, you can block all STDOUT:

RSpec.configure do |config|
  original_stderr = $stderr
  original_stdout = $stdout
  config.before(:all) do
    # Redirect stderr and stdout
    $stderr = File.open(File::NULL, "w")
    $stdout = File.open(File::NULL, "w")
  config.after(:all) do
    $stderr = original_stderr
    $stdout = original_stdout