Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do you test code that forks using rspec

I have the following code

  def start_sunspot_server
    unless @server
      pid = fork do
        STDERR.reopen("/dev/null")
        STDOUT.reopen("/dev/null")
        server.run
      end

      at_exit { Process.kill("TERM", pid) }

      wait_until_solr_starts
    end
  end

How would I effectively go about testing it using rspec?

I thought something along

Kernel.should_receive(:fork)
STDERR.should_receive(:reopen).with("/dev/null")
STDOUT.should_receive(:reopen).with("/dev/null")
server.should_receive(:run)

etc

like image 530
ErsatzRyan Avatar asked May 28 '11 00:05

ErsatzRyan


People also ask

How do I run a test in RSpec?

To run a single Rspec test file, you can do: rspec spec/models/your_spec. rb to run the tests in the your_spec. rb file.

What are RSpec tests?

RSpec is a testing tool for Ruby, created for behavior-driven development (BDD). It is the most frequently used testing library for Ruby in production applications. Even though it has a very rich and powerful DSL (domain-specific language), at its core it is a simple tool which you can start using rather quickly.

How do I run a Rails test?

2.7 The Rails Test Runner We can run all of our tests at once by using the bin/rails test command. Or we can run a single test file by passing the bin/rails test command the filename containing the test cases. This will run all test methods from the test case.

How do you test a method in Ruby?

Most methods can be tested by saying, “When I pass in argument X, I expect return value Y.” This one isn't so straightforward though. This is more like “When the user sees output X and then enters value V, expect subsequent output O.” Instead of accepting arguments, this method gets its value from user input.


2 Answers

I'm confused by the @server instance variable and server method in your example, but here is an example that should help you get where you're trying to go:

class Runner
  def run
    fork do
      STDERR.reopen("/dev/null")
    end
  end
end

describe "runner" do
  it "#run reopens STDERR at /dev/null" do
    runner = Runner.new

    runner.should_receive(:fork) do |&block|
      STDERR.should_receive(:reopen).with("/dev/null")
      block.call
    end

    runner.run
  end
end

The key is that the fork message is sent to the Runner object itself, even though its implementation is in the Kernel module.

HTH, David

like image 146
David Chelimsky Avatar answered Sep 28 '22 07:09

David Chelimsky


David's solution didn't work for us. Maybe it's because we're not using RSpec 2?

Here's what did work.

def run
  fork do
    blah
  end
end

describe '#run' do
  it 'should create a fork which calls #blah' do
    subject.should_receive(:fork).and_yield do |block_context|
      block_context.should_receive(:blah)
    end

    subject.run_job
  end
end

I'm not sure how this would apply when calling a constant, such as STDERR, but this was the only way we were able to accomplish fork testing.

like image 24
user210977 Avatar answered Sep 28 '22 08:09

user210977