Is there a way to use a matcher like 'Verify' in rspec? - ruby

So far I'm using 'expect' in my test framework which will stop the execution when it meets a fail condition. I want something like, the execution should happen even if it meets the fail condition. I could see that there is a matcher called 'Verify' in rspec where I need to inherit 'Test::Unit::TestCase' class, but my issue is that, I need the matcher in my spec file which is not written under a ruby class.

There isn't a way to do this with RSpec, out of the box.
Because Rspec is designed to test small, isolated logics.
On failure, Rspec matchers raise Error, So what you can do is to wrap the matchers in a rescue block.
To satisfy your need, you could write a wrapper like this:
def report_last(&block)
begin
yield
rescue Exception => e
puts "Failure: #{e}"
end
end
In your test case:
describe Calculator do
it “should add 2 numbers” do
report_last do
expect(described_class.new(2, 3).sum)to eq(5)
end
end
end

Related

In RSpec, how can I mock a method called with a constant argument?

I'm creating a gem that will have a constant in whatever app it is being used in (after a generator is run), but that constant doesn't exist in the gem itself. I'm having an issue with RSpec inside the gem not skipping over the part of code that is calling the constant. A simple example of what is going on is below.
class Foo
def self.do_something
Bar.send(FakeConstant.name) #Bar.send is a valid class and method
end
end
foo_spec.rb
it 'does something'
expect(Bar).to receive(send).and_return('skipped!')
Foo.do_something
end
rspec output
NameError: uninitialized constant FakeConstant
I want to write the test so that it skips over the Bar.send call completely so that it never knows that there is a bad constant inside of it. There really isn't a good way to get around this.
RSpec's stub_const method allows you to stub a constant:
it 'does something'
stub_const(FakeConstant, double(name: "Fakey McFakerson"))
expect(Bar).to receive(send).and_return('skipped!')
Foo.do_something
end
More here: https://www.relishapp.com/rspec/rspec-mocks/docs/mutating-constants/stub-defined-constant
That said, I agree with BroiSatse that it would be probably be nicer to provide a more dynamic means of getting that information into your code that could be manipulated in tests with less trickery.

Activerecord rescue

I have a ruby app that uses ActiveRecord but not Rails.
I want to rescue from all database errors which in my case can include a SQLite3::BusyException.
Is there a better way than to wrap every Model.find, Model.where, obj.save, etc in a rescue?
I thought adding a module to every model that monkey patches/hijacks DB actions such as, but where appears complex and something not to be trifled with:
def where
super
rescue ActiveRecord::RecordNotFound
rescue SQLite3::BusyException => e
p [:warning, e.message]
end
When using Celluloid I ran into a similar issue where I needed to trap errors due to the connection pooling not working correctly with how Celluloid was using fibers. I used something like the following wrapper method to help make sure errors were trapped and resolved the connection reaping in my code. For your scenario, it could look like this:
module TrackActiveRecordErrors
def db(&block)
begin
yield block
rescue StandardError => e
p [:warning, e.message]
# ... and other sort of logging, alerting you'd like
raise e
ensure
# Put your clean-up code here
end
end
end
In classes you want to use this wrapper:
class DoSomething
include TrackActiveRecordErrors
def find_something(id)
db do
a_something = Model.find(id)
end
a_something
end
end
It's not pretty, but it's a lot easier than trying to tune AR's magic in the model classes.

Rspec - How to write specs for a chain of methods

I'm learning rspec, and I'm wondering what the most effective way to write specs for a method that calls a chain of other methods. For example:
class Example1
def foo(dependency)
dependency.bar("A")
dependency.baz("B")
dependency.bzz("C")
end
end
Ideally I would like to write specs like this:
it "should call bar" do
ex = Example1.new
dep = mock
dep.should_receive(:bar).with("A")
ex.foo(dep)
end
it "should call baz"
...
it "should call bzz"
...
When I do that, however, I (understandably) get exceptions like 'unexpected method call baz'.
So what's the best way to deal with that? I have come up with a couple of ideas but I don't know if any of them are good.
Make the mock dependency an "as_null_object" so it ignores the extra calls. (Down side - if I was calling unwanted random stuff on that object, I wouldn't know it)
Stub out the two unused dependency method calls in each spec (Down side - feels very DRY)
Stub out all three dependency calls in a 'before' (Down side - puts a lot of junk in the 'before')
It sounds like you have already worked out which options RSpec gives you. I would go with option 1 and use as_null_object. It's true that you might be missing other random method calls on that object but I would be ok with that if the point of each of these tests was simply to assert that a particular method was being called, especially if I have higher level integration tests covering this method.
If you really need to verify that no other methods are called on dependency then option 3 may make sense but such tests can be brittle when implementation changes.
As an aside, to make your test a little simpler you can use subject to avoid explicitly instantiating Example1 (assuming you are using a describe Example1 block), e.g.:
subject.foo(dep)
(However see discussion in comments - an implicit subject can hide intention).
RSpec has a feature called stub_chain: https://www.relishapp.com/rspec/rspec-mocks/v/2-0/docs/stubs/stub-a-chain-of-methods
What about testing them all in one example?
it "should call bar"
ex = Example1.new
dep = mock
dep.should_receive("bar").with("A")
dep.should_receive("baz").with("B")
dep.should_receive("bzz").with("C")
ex.foo(dep)
end
I believe you can use RSpec to verify the order in which they are called, if that matters.
However, this kind of approach often indicate that there is a problem with how the code is written, e.g. a Law Of Demeter violation. In your example, foo should be a methed on the dependency's class.
I would test this code in this way:
describe "checking foo method" do
before(:each) do
#ex = Example1.new
#test = ClassOfDependency.any_instance
#test.as_null_object
end
after(:each) do
#ex.foo(dependency)
end
it "should call bar method" do
#test.should_receive(:bar).with("A")
end
it "should call baz method" do
#test.should_receive(:baz).with("B")
end
it "should call bzz method" do
#test.should_receive(:bzz).with("C")
end
end
But I'm not sure that it will work, hope it'll give you some ideas.

Rspec: when the matcher fails

I have a Rails project and use RSpec as a testing framework. What I need is to subscribe to the event when some matcher fails, e.g. I got this:
true.should be_false
I want to do some action on every fail. Is this functionality provided by the RSpec?
You can monkey-patch this behavior into RSpec::Core::Example class:
require 'spec_helper'
class RSpec::Core::Example
def failed?
!#exception.nil?
end
end
describe "my_tested_things" do
...
end
Then you can ensure it will run your desired code after all failing matches:
after(:each) do
run_my_code if example.failed?
end
Check out the hooks, not certain it will help but where it passes example in to the block (in the docs) you may be able to get the result...
https://www.relishapp.com/rspec/rspec-core/v/2-0/docs/hooks

How to mock an TCP connecting in Cucumber

I want to test one program which can capture and send IP packets to some clients, so how to mock request or client in Cucumber? thanks
Normally I would answer the question with the cavet that it's a bad idea but this is such a bad idea I'm only going to answer half of it, how to mock in Cucumber generically.
You see Cucumber is meant to be a total test from the outside in so it's meant to completely run your code without any test doubles. The whole point is you are not unit testing but are testing your whole application.
"We recommend you exercise your whole stack when using Cucumber. [However] you can set up mocks with expectations in your Step Definitions." - Aslak Hellesøy, Creator of Cucumber
Granted you can do this but you are going to need to write your own the TCPServer and TCPSocket classes to avoid using the network and that can actually introduce bugs since your writing specs against your mock Net classes not the actual Net classes. Again, not a good idea.
Enough yapping, here's how to use mocks in Cucumber. (I'm going to assume you have a basic understanding of Cucumber and Ruby so I will skip some steps like how to require your class files in Cucumber.)
Let's say you have the following classes:
class Bar
def expensive_method
"expensive method called"
end
end
class Foo
# Note that if we don't send a bar it will default to the standard Bar class
# This is a standard pattern to allow test injection into your code.
def initialize(bar=Bar.new)
#bar = bar
puts "Foo.bar: #{#bar.inspect}"
end
def do_something
puts "Foo is doing something to bar"
#bar.expensive_method
end
end
You should have the Bar and Foo classes required in your features/support/env.rb file but to enable RSpec mocks you need to add the following line:
require 'cucumber/rspec/doubles'
Now create a feature file like this one:
Feature: Do something
In order to get some value
As a stake holder
I want something done
Scenario: Do something
Given I am using Foo
When I do something
Then I should have an outcome
And add the steps to your step definitions file:
Given /^I am using Foo$/ do
# create a mock bar to avoid the expensive call
bar = double('bar')
bar.stub(:expensive_method).and_return('inexpensive mock method called')
#foo = Foo.new(bar)
end
When /^I do something$/ do
#outcome = #foo.do_something
# Debug display of the outcome
puts ""
puts "*" * 40
puts "\nMocked object call:"
puts #outcome
puts ""
puts "*" * 40
end
Then /^I should have an outcome$/ do
#outcome.should_not == nil
end
Now when you run your feature file you should see:
****************************************
Mocked object call:
inexpensive mock method called
****************************************

Resources