I 'm trying to write an RSpec test for this service. The service below essentially just makes a call to some endpoint and then create data in the postgres DB.
class SomeService
API_URL = "someEndPoint"
def process
get_reviews
end
def get_reviews
conn = Faraday.new(url: "#{APIURL}/#{ENV["ID"]}/reviews?language=en&stars=5") do |faraday|
faraday.headers["apikey"] = ENV["KEY"]
faraday.adapter Faraday.default_adapter
end
response = conn.get
imported_reviews = []
results = JSON.parse(response.body)
results["reviews"].each do |item|
review = SomeModel.create(
title: item["title"],
body: item["text"],
posted_at: item["createdAt"],
link: "https://somelink.com/#{item["id"]}",
display_name: item["consumer"]["displayName"]
)
imported_reviews << review
end
imported_reviews
end
end
My model is just the boilerplate model shown as:
class SomeModel < ApplicationRecord
end
This is my spec file some_service_spec.rb. I've written plenty of tests in JEST but it's just so foreign to me in Ruby.
# frozen_string_literal: true
require 'rails_helper'
describe TrustpilotService do
describe "#process" do
context 'with valid API_KEY' do
before :all do
WebMock.allow_net_connect!
end
after :all do
WebMock.disable_net_connect!(allow_localhost: true)
end
it "should import reviews to database" do
key = "90e0dbc7160d4024a1f12bc24b3d1def" #fake key#
some_review = create(title: 'Blah', body: 'Blah blah', posted_at: '2019-09-30T20:35:14Z', link: 'https://somelink.com/reviews/asdf123', display_name: 'Jane Doe')
some_review.save!
service = described_class.new
expect{ service.process }.to change{ SomeModel.count }
end
end
end
end
Edit added my factory for reference
FactoryBot.define do
factory :trustpilot_review do
end
end
Gem File
group :test do
gem "capybara", "~> 3.29.0"
gem 'database_cleaner'
gem 'factory_bot_rails'
gem 'rails-controller-testing'
gem 'rspec-rails', '~> 3.8'
gem 'rspec-snapshot', '~> 0.1.2'
gem "shoulda-matchers"
gem "simplecov", require: false
gem 'timecop'
gem "webdrivers"
gem 'webmock'
end
I essentially was just trying to replicate another spec file that was testing a service that does sort of the same thing but I'm getting Factory not registered: as an error. I created a factory but not entirely sure what to even put in it. All of the info on RSPEC out there is kind of outdated. As you can tell, I'm pretty new to Ruby so any help is appreciated.
If this is the way you are calling your factory, then you missed naming the factory:
some_review = create(title: 'Blah', body: 'Blah blah', posted_at: '2019-09-30T20:35:14Z', link: 'https://somelink.com/reviews/asdf123', display_name: 'Jane Doe')
Try
some_review = create(:trustpilot_review, title: 'Blah', body: 'Blah blah', posted_at: '2019-09-30T20:35:14Z', link: 'https://somelink.com/reviews/asdf123', display_name: 'Jane Doe')
Also it seems to me that the title, link, etc, should mostly be in the factory definition which is the point of factories.
If you want to use factory name with different name of model name. then need to add class_name like below:
FactoryBot.define do
factory :trustpilot_review, class: 'SomeModel' do
end
end
Related
I'm new to rails testing,i want to test my rails controller api.
I using gems rails-rspec ,capybara and database-cleaner like this in my Gemfile:
group :development, :test do
gem 'rspec-rails', '~> 3.7'
end
group :test do
gem 'database_cleaner'
gem 'capybara'
end
And in my spec folder i create a controller and create a user_controller_spec.rb inside my api folder and want to test create a user with valid parameters and write a code like this:
RSpec.describe "API V1 Users", type: 'request' do
describe "POST /api/v1/users" do
context "with valid parameters" do
let(:valid_params) do
{
fname: "Riya",
lname: "******",
email: "*******.com",
password: "",
contact: "2144333",
country_code:"91",
address: "Sector 63",
city: "Noida",
state: "UP",
country: "India",
zipcode: "23001",
role: "***",
image: ""
}
end
it "creates a new user" do
expect { post "/api/v1/users", params: valid_params}
expect(response).to have_http_status(:ok) # it's use for code 200
end
it "creates a user with the correct attributes" do
post "/api/v1/users", params: valid_params
expect(User.last).to have_attributes valid_params
end
end
context "with invalid parameters" do
# testing for validation failures is just as important!
# ...
end
end
end
But it gives me error :
Failure/Error: expect(User.last).to have_attributes valid_params expected nil to respond to :fname, :lname, :email, :password, :contact
To be sure that your post query create an user you can write it like this:
expect { post "/api/v1/users", params: valid_params}.to change(User, :count).by(1)
It test if a user is added to the database.
I am trying to write an Rspec test for the first time, my model test worked out fine, but I have problems with my controller test. Which seems weird. For my model test, I'm following the example from: https://gist.github.com/kyletcarlson/6234923
I am given the infamous Factory not registered: error. The log is below:
1) ProductsController POST create when given all good parameters
Failure/Error: post :create, product: attributes_for(valid_product)
ArgumentError:
Factory not registered: #<Product:0x007fc47275a330>
# ./spec/controllers/products_controller_spec.rb:12:in `block (4 levels) in <top (required)>'
I have tried solutions given by others and now my files look like this:
Gemfile
group :test, :development do
gem 'shoulda'
gem 'rspec-rails'
gem 'factory_girl_rails'
gem 'database_cleaner'
end
rails_helper.rb
ENV["RAILS_ENV"] ||= 'test'
require 'spec_helper'
require File.expand_path("../../config/environment", __FILE__)
require 'rspec/rails'
require 'factory_girl_rails'
...
RSpec.configure do |config|
...
config.include FactoryGirl::Syntax::Methods
end
/spec/factories/products.rb
FactoryGirl.define do
factory :product do
sequence(:name) { |n| "test_name_#{n}" }
price "1.50"
description "Test Description"
end
end
/spec/controllers/products_controller_spec.rb
require 'rails_helper'
describe ProductsController do
let(:valid_product) { create(:product) }
let(:invalid_product) { create(:product, name: nil, price: 0, description: test_description) }
describe "POST create" do
context 'when given all good parameters' do
before(:each){
post :create, product: attributes_for(valid_product)
}
it { expect(assigns(:product)).to be_an_instance_of(Product) }
it { expect(response).to have_http_status 200 }
end
end
end
Any help will be appreciated. Thanks.
*Updated to include factories details, that was already implemented before question was posed.
On this line
post :create, product: attributes_for(valid_product)
You are calling attributes_for passing valid_product which is an actual instance of Product, hence the error message.
I suspect you intended to write
post :create, product: attributes_for(:product)
You need to specify factory separately. Create spec/factories/products.rb with content:
FactoryGirl.define do
factory :product do
name 'My awesome product'
price 100
description 'Just a simple awesome product'
# add there attributes you need
end
end
Simplecov detected that I was missing some tests on my lib/api_verson.rb class:
class ApiVersion
def initialize(version)
#version = version
end
def matches?(request)
versioned_accept_header?(request) || version_one?(request)
end
private
def versioned_accept_header?(request)
accept = request.headers['Accept']
accept && accept[/application\/vnd\.#{Rails.application.secrets.my_app_accept_header}-v#{#version}\+json/]
end
def unversioned_accept_header?(request)
accept = request.headers['Accept']
accept.blank? || accept[/application\/vnd\.#{Rails.application.secrets.my_app_accept_header}/].nil?
end
def version_one?(request)
#version == Rails.application.secrets.my_app_default_api_version && unversioned_accept_header?(request)
end
end
This class is used by the routes file to help setup api versions:
namespace :api, path: "", defaults: {format: :json} do
scope module: :v1, constraints: ApiVersion.new(1) do
get '/alive', to: 'api#alive'
end
scope module: :v2, constraints: ApiVersion.new(2) do
get '/alive', to: 'api#alive'
end
end
This setup was ported from versioning_your_ap_is.
I am trying to test the methods here that simplecov is reporting as failures:
require 'spec_helper'
describe ApiVersion do
before(:each) do
#apiversion = ApiVersion.new(1)
#request = ActionController::TestRequest.new(host: 'localhost')
#request.headers["Accept"] = "application/vnd.#{Rails.application.secrets.my_app_accept_header}-#{Rails.application.secrets.my_app_default_api_version}+json"
end
describe 'Method #versioned_accept_header =>' do
it 'Should return the correct accept header version' do
binding.pry
end
end
end
I am trying to build this first test to attempt??? to #apiversion.send(:unversioned_accept_header, #request) and I am getting the error:
#apiversion.send(:unversioned_accept_header, #request)
NoMethodError: undefined method `unversioned_accept_header' for #<ApiVersion:0x007fae009bdad8 #version=1>
from (pry):1:in `block (3 levels) in <top (required)>'
Basically the following methods are flagged: "matches?, versioned_accept_header?, unversioned_accept_header?, and version_one?"
I am not the rockstar at rspec and could use some pointers here. Thank you for your help.
Btw, this is a rails 4 application running:
group :development, :test do
gem 'pry'
gem 'pry-doc'
gem 'pry-debugger'
gem 'pry-rails'
gem 'pry-plus'
gem 'pry-rescue'
gem 'pry-stack_explorer'
gem 'pry-clipboard'
gem 'pry-nav'
gem 'rspec-rails'
gem 'factory_girl_rails'
gem 'faker'
gem 'seedbank'
gem 'capybara'
end
group :test do
gem 'simplecov', '~> 0.7.1'
gem 'shoulda-matchers'
gem 'spork-rails'
gem 'database_cleaner'
gem 'email_spec'
gem 'timecop'
gem 'json_spec'
end
You run this code
#apiversion.send(:unversioned_accept_header, #request)
but you have method:
def unversioned_accept_header?(request)
accept = request.headers['Accept']
accept.blank? || accept[/application\/vnd\.#{Rails.application.secrets.my_app_accept_header}/].nil?
end
try change
#apiversion.send(:unversioned_accept_header, #request) -> #apiversion.send(:unversioned_accept_header?, #request)
or change method name
def unversioned_accept_header? -> def unversioned_accept_header
I am trying to create my first controller test using FactoryGirl for my Rails application, but I keep retrieving the following error:
uninitialized constant FactoryGirl
My Factories.rb file looks like this:
FactoryGirl.define do
factory :offer, class: "Offer" do |f|
f.title "Some title"
f.description "SomeDescription"
end
end
And my controller test looks like this:
require 'spec_helper'
describe OffersController do
def valid_session
{}
end
describe "GET index" do
before {
#offer = FactoryGirl.create(:offer)
}
it "assigns all offers as #offers" do
get :index, {}, valid_session
assigns(:offers).should eq([#offer])
end
end
end
My Gemfile looks like this:
group :development, :test do
gem 'sqlite3'
gem 'rspec-rails'
gem 'capybara', '1.1.2'
gem 'factory_girl_rails', '>= 4.1.0', :require => false
end
What might I be missing since FactoryGirl isn't present?
You propably forgotten to require factory_girl in spec_helper.rb.
I'm attempting to follow railstutorial.org, and am currently on Chapter 7, where you start using factories: http://railstutorial.org/chapters/modeling-and-viewing-users-two#sec:tests_with_factories
I'm using Rails 3.0.1 and ruby-1.9.2-p0
I can't for the life of me get my rspec tests to pass though, the error i get is
Failures:
1) UsersController GET 'show' should be successful
Failure/Error: #user = Factory(:user)
undefined method `Factory' for #<RSpec::Core::ExampleGroup::Nested_2::Nested_1:0x00000101cc5608>
# ./spec/controllers/users_controller_spec.rb:9:in `block (3 levels) in <top (required)>'
my factories.rb looks like this:
# By using the symbol ':user', we get Factory Girl to simulate the User model.
Factory.define :user do |user|
user.name "Michael Hartl"
user.email "mhartl#example.com"
user.password "foobar"
user.password_confirmation "foobar"
end
and this is my users_controller_spec.rb file:
require 'spec_helper'
describe UsersController do
render_views
describe "GET 'show'" do
before(:each) do
#user = Factory(:user)
end
it "should be successful" do
get :show, :id => #user
response.should be_success
end
here is my Gemfile, if it helps:
source 'http://rubygems.org'
gem 'rails', '3.0.1'
# Bundle edge Rails instead:
# gem 'rails', :git => 'git://github.com/rails/rails.git'
gem 'sqlite3-ruby', :require => 'sqlite3'
gem 'gravatar_image_tag'
group :development do
gem 'rspec-rails'
gem 'annotate-models'
end
group :test do
gem 'rspec'
gem 'webrat'
gem 'spork'
gem 'factory_girl_rails'
end
As per the latest version of Factory Girl (currently v4.0.0)
rewrite factories.rb
FactoryGirl.define do
factory :user do
name "Michael Hartl"
email "mhartl#example.com"
password "foobar"
password_confirmation "foobar"
end
end
then call it from your users controller specs as:
FactoryGirl.create(:user)
I got this exact same error message. I just restarted my Spork server and Autotest and everything went green for me.
Maybe you should try the new syntax (see github readme of factory girl)
FactoryGirl.define :user do |user|
user.name "Michael Hartl"
user.email "mhartl#example.com"
user.password "foobar"
user.password_confirmation "foobar"
end
In your spec use
#user = FactoryGirl(:user)
instead of
#user = Factory(:user)
I had this problem, but it was because I had placed the factory girl gem under the development section instead of the test section of the Gemfile. Once under the test section, it worked. One difference I note between my entry and yours is that mine specifies 1.0:
group :test do
gem 'rspec-rails', '2.6.1'
gem 'webrat', '0.7.1'
gem 'factory_girl_rails', '1.0'
end
For me I had to add require 'factory_girl' to test_helper.rb
My solution: I've accidentally included it in the :development block, and simply had to move it to the :test block
(I've listed it here, because it might help someone who doesn't follow the tutorial correctly)
I have done so,
add require 'factory_girl' to test_helper.rb and
#user = FactoryGirl.create(:user)
For those finding this page now: note where you once used "FactoryGirl" you must now use "FactoryBot" in your tests. From the thoughtbot announcement page:
"We’re renaming factory_girl to factory_bot (and factory_girl_rails to
factory_bot_rails). All the same functionality of factory_girl, now
under a different name."
More details here:
https://robots.thoughtbot.com/factory_bot
I was determined to use the newest version of Factory Girl, so I tried to adapt the code. Didn't work for me, so I used
gem 'factory_girl_rails', '1.0'
in the Gemfile to lock the version at 1.0
bundle update
restart spork and autotest and it worked.