Test between describe '...' do ... end does not take into account the test - ruby-on-rails

I have a test that looks like this:
class PageTest < ActiveSupport::TestCase
describe "test" do
test "should not save without attributes" do
page = Page.new
assert !page.save
end
end
end
When running the tests, I get 0 tests, 0 assertions. If I remove the describe "test" do, I get the 1 test, 1 assertions. So I have the feeling that the describe "..." do is actually making the test disappear.
What is going on here? What am I missing?

Looks like you're mixing up minitest specs and ActiveSupport::TestCase. If you check the rails guides on testing the test method is explained but it's not used with describe.
Rails adds a test method that takes a test name and a block. It
generates a normal MiniTest::Unit test with method names prefixed with
test_. So,
test "the truth" do
assert true
end
acts as if you had written
def test_the_truth
assert true
end
The describe syntax is explained in the minitest docs under the spec section and is used with it (and not test). Like so:
describe "when asked about cheeseburgers" do
it "must respond positively" do
#meme.i_can_has_cheezburger?.must_equal "OHAI!"
end
end

Related

Rerun Ruby test suite with feature flag

I have a class with 20 rspec tests, and the result should be the exact same whether my main logic goes through a feature flag or not.
I am wondering what the best way to test this suite so that on Jenkins it can test both directions?
I want to avoid having to copy paste the 20 tests again, just to add another line like:
featureFlag.enabled = True
Right before the test logic.
Is this possible? Thanks
It depends which test framework you use? RSpec? Minitest?
In RSpec you could for instance use a shared example
RSpec.shared_examples "some example" do |flag|
before do
featureFlag.enabled = flag
end
it "works with feature flag '#{flag}'" do
expect(something).to be true
end
end
RSpec.describe SomeClass do
include_examples "some example", true
include_examples "some example", false
end
In Minitest you can just use a module.
https://relishapp.com/rspec/rspec-core/docs/example-groups/shared-examples

How to write rspec for rails jobs

Hi i am working with a RoR project with ruby-2.5.0 and rails 5. I am using AWS SQS. I have created a job as follows:-
class ReceiptsProcessingJob < ActiveJob::Base
queue_as 'abc'
def perform(receipt_id)
StoreParserInteractor.process_reciept(receipt_id)
end
end
Now i want to write unit test for it. I tried like:-
# frozen_string_literal: true
require 'rails_helper'
describe ReceiptsProcessingJob do
describe "#perform_later" do
it "scan a receipt" do
ActiveJob::Base.queue_adapter = :test
expect {
ReceiptsProcessingJob.perform_later(1)
}.to have_enqueued_job
end
end
end
But it doesnot cover StoreParserInteractor.process_reciept(receipt_id). Please help how can i cover this. Thanks in advance.
The example is testing the job class. You need to write a spec for StoreParserInteractor and test the method process_reciept.
Something along the lines of (pseudo code):
describe StoreParserInteractor do
describe "#process_receipt" do
it "does that" do
result = StoreParserInteractor.process_receipt(your_data_here)
expect(result to be something)...
end
end
end
But, the Rails guide suggests this kind of test:
assert_enqueued_with(job: ReceiptsProcessingJob) do
StoreParserInteractor.process_reciept(receipt_id)
end
Maybe this increases code coverage as well.
In my opinion, you shouldn't actually test the ActiveJob itself, but the logic behind it.
You should write a test for StoreParserInteractor#process_reciept. Think of ActiveJob as an "external framework" and it is not your responsibility to test the internals of it (e.g. if the job was enqueued or not).
As kitschmaster said, don't test ActiveJob classes, in short

rspec not reporting line number of error

For almost all my specs, when rspec reports an error, it informs me of the line number at the end of the path e.g.
rspec ./spec/controllers/eclubs_controller_spec.rb:21
However in one of my specs, it reports the error location like this
rspec ./spec/controllers/eclubs/members_controller_spec.rb[1:1:2:3:1]
which may make sense in terms of the nesting of blocks but frankly is rather cryptic.
The top part of the spec that works looks like this
require 'rails_helper'
describe EclubsController do
and the one that does not work looks like this
require 'rails_helper'
describe Eclubs::MembersController do
The only difference I can see in the two files is that one controller is namespaced, but I have other namespaced controllers that report the error line correctly.
What is causing this?
RSpec uses the example id when the line number is not sufficiently unique to identify the example in question.
This can happen when examples are dynamically defined, for example in a loop:
(0..10).each do |i|
it do
expect(i).to_not eq(5)
end
end
# rspec './my_spec.rb[1:6]'
Or when using a shared example group:
RSpec.shared_examples_for "not equal 5" do |i|
it do
expect(i).to_not eq(5)
end
end
RSpec.describe do
it_behaves_like "not equal 5", 5
it_behaves_like "not equal 5", 4
end
# rspec './my_spec.rb[2:1:1]'

Best practice for reusing code in Rspec?

I'm writing integration tests using Rspec and Capybara. I've noticed that quite often I have to execute the same bits of code when it comes to testing the creation of activerecord options.
For instance:
it "should create a new instance" do
# I create an instance here
end
it "should do something based on a new instance" do
# I create an instance here
# I click into the record and add a sub record, or something else
end
The problem seems to be that ActiveRecord objects aren't persisted across tests, however Capybara by default maintains the same session in a spec (weirdness).
I could mock these records, but since this is an integration test and some of these records are pretty complicated (they have image attachments and whatnot) it's much simpler to use Capybara and fill out the user-facing forms.
I've tried defining a function that creates a new record, but that doesn't feel right for some reason. What's the best practice for this?
There are a couple different ways to go here. First of all, in both cases, you can group your example blocks under either a describe or context block, like this:
describe "your instance" do
it "..." do
# do stuff here
end
it "..." do
# do other stuff here
end
end
Then, within the describe or context block, you can set up state that can be used in all the examples, like this:
describe "your instance" do
# run before each example block under the describe block
before(:each) do
# I create an instance here
end
it "creates a new instance" do
# do stuff here
end
it "do something based on a new instance" do
# do other stuff here
end
end
As an alternative to the before(:each) block, you can also use let helper, which I find a little more readable. You can see more about it here.
The very best practice for your requirements is to use Factory Girl for creating records from a blueprint which define common attributes and database_cleaner to clean database across different tests/specs.
And never keep state (such as created records) across different specs, it will lead to dependent specs. You could spot this kind of dependencies using the --order rand option of rspec. If your specs fails randomly you have this kind of issue.
Given the title (...reusing code in Rspec) I suggest the reading of RSpec custom matchers in the "Ruby on Rails Tutorial".
Michael Hartl suggests two solutions to duplication in specs:
Define helper methods for common operations (e.g. log in a user)
Define custom matchers
Use these stuff help decoupling the tests from the implementation.
In addition to these I suggest (as Fabio said) to use FactoryGirl.
You could check my sample rails project. You could find there: https://github.com/lucassus/locomotive
how to use factory_girl
some examples of custom matchers and macros (in spec/support)
how to use shared_examples
and finally how to use very nice shoulda-macros
I would use a combination of factory_girl and Rspec's let method:
describe User do
let(:user) { create :user } # 'create' is a factory_girl method, that will save a new user in the test database
it "should be able to run" do
user.run.should be_true
end
it "should not be able to walk" do
user.walk.should be_false
end
end
# spec/factories/users.rb
FactoryGirl.define do
factory :user do
email { Faker::Internet.email }
username { Faker::Internet.user_name }
end
end
This allows you to do great stuff like this:
describe User do
let(:user) { create :user, attributes }
let(:attributes) { Hash.new }
it "should be able to run" do
user.run.should be_true
end
it "should not be able to walk" do
user.walk.should be_false
end
context "when user is admin" do
let(:attributes) { { admin: true } }
it "should be able to walk" do
user.walk.should be_true
end
end
end

RSpec Stub doesn't cover multiple nested Describe blocks

I have a test suite structured as follows:
describe ... do
[list of dates].each do
describe
before(:all) do
base_date = ...
end
describe ... do
[list of times].each do
describe ... do
before(:all) do
base_time = base_date + ...
DateTime.stub!(:now).and_return(base_time)
end
describe ... do
<test using records within date-time range based on base_time>
end
describe ... do
<another test using records within date-time range based on base_time>
end
end
end
end
end
end
end
The first test has DateTime(now) == base_time, but the second test as DateTime(now) == my computer's date-time, indicating that the stub is no longer in effect. Moving the stub! call into each describe loop resolves the problem, but I would like to understand why it doesn't work as written.
The reason lies probably elsewhere, stubs work fine with multiple nested describe blocks. Maybe :all vs :each is the problem: before(:all) is executed once before all describe blocks are executed, while before(:each) is executed each time before a describe block is executed.
Or maybe it has something to do with stubbing DateTime, have you tried
DateTime.any_instance.stub(:now).and_return(base_time)

Resources