Rspec + Factory girl (without rails!) - ruby

I am using Rspec with selenium-webdriver gem to test a web app. And I wanted to unclude factories in my tests to emulate users and not to create a user manually each time.
So, I made gem install factory_girl, added required lined in my spec_helper, created a factory and included some lines in my spec file. And when running the test I get an error
Failure/Error: FactoryGirl.build(:user)
NameError:
uninitialized constant User
Here is my spec_helper.rb
RSpec.configure do |config|
config.include FactoryGirl::Syntax::Methods
config.expect_with :rspec do |expectations|
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
end
My factories.rb file:
FactoryGirl.define do
factory :user do
name "testuser"
password "freestyle"
inventory true
end
end
And my test_spec file:
require "json"
require "selenium-webdriver"
require "rspec"
require "factory_girl"
FactoryGirl.find_definitions
include RSpec::Expectations
describe "MallSpec" do
before(:all) do
FactoryGirl.build(:user)
#driver = Selenium::WebDriver.for :firefox
#base_url = "http://localhost:9000/"
#accept_next_alert = true
#driver.manage.timeouts.implicit_wait = 30
#driver.manage.window.resize_to(1301, 744)
#verification_errors = []
end
My spec_file is in the root dir of the project. my factories.rb file is in /spec dir as well as the test_spec.rb itself.
Can anyone help me with this issue or point what i am doing wrong?

If you don't actually have a User class but you want to use FactoryGirl to generate the attributes, you can override the class:
require "ostruct"
FactoryGirl.define do
factory :user, class: OpenStruct do
name "testuser"
password "freestyle"
inventory true
# This isn't necessary, but it will prevent FactoryGirl from trying
# to call #save on the built instance.
to_create {}
end
end
You can then use attributes_for if you just want a Hash, or create if you want an object that responds to methods like name.
You can use a library like Hashie::Mash if you want to generate JSON for use in your API:
factory :user, class: Hashie::Mash do
# ...
end
# In your tests:
user_json = create(:user).to_json

And when running the test I get an error Failure/Error:
FactoryGirl.build(:user) NameError: uninitialized constant User
Your User class has to be defined. The following is a test with no User class defined:
require 'factory_girl'
RSpec.configure do |config|
config.include FactoryGirl::Syntax::Methods
end
FactoryGirl.define do
factory :user do
name 'Alice'
age 10
end
end
describe "MallSpec" do
let(:test_user) { FactoryGirl.build(:user) }
describe "user's name" do
it "equals 'Alice'" do
expect(test_user.name).to eq('Alice')
end
end
end
--output:--
$ rspec 1.rb
F
Failures:
1) MallSpec user's name equals 'Alice'
Failure/Error: let(:user) { FactoryGirl.build(:user) }
NameError:
uninitialized constant User
...
Adding a definition for the User class:
require 'factory_girl'
#====NEW CODE=====
class User
attr_accessor :name, :age
end
#=================
RSpec.configure do |config|
config.include FactoryGirl::Syntax::Methods
end
FactoryGirl.define do
factory :user do
name 'Alice'
age 10
end
end
describe "MallSpec" do
let(:test_user) { FactoryGirl.build(:user) }
describe "user's name" do
it "equals 'Alice'" do
expect(test_user.name).to eq('Alice')
end
end
end
--output:--
$ rspec 1.rb
.
Finished in 0.0024 seconds (files took 0.35197 seconds to load)
1 example, 0 failures
I expect that the factory() method here:
factory :user do
name 'Alice'
age 10
end
...does something like this:
def factory(model_name)
target_class = constant_get(model_name.capitalize)
...in order to construct a real instance of the User class. In other words, factory_girl constructs instances of classes that already exist in your app--factory_girl does not mock a class.

Related

Uninitialized constant NameError in Rspec

When I run rails c, I can call the following class and the method works:
test = SlackService::BoardGameNotifier
test.create_alert("test")
>>method works
I'm trying to set this up in rspec like this:
require 'spec_helper'
require 'slack-notifier'
RSpec.describe SlackService::BoardGameNotifier do
describe '#notify' do
#notifier = SlackService::BoardGameNotifier
it 'pings Slack' do
error = nil
message = "test"
expect(notifier).to receive(:ping).with(message)
notifier.send_message()
end
end
end
But I keep getting the error:
NameError:
uninitialized constant SlackService
Does this have to do with how I set up the module?
My current setup:
slack_service/board_game_notifier.rb
module SlackService
class BoardGameNotifier < BaseNotifier
WEBHOOK_URL = Rails.configuration.x.slack.url
DEFAULT_OPTIONS = {
channel: "board-games-channel",
text: "board games alert",
username: "bot",
}
def create_alert(message)
message #testing
end
end
end
slack_service/base_notifier.rb
module SlackService
class BaseNotifier
include Singleton
def initialize
webhook_url = self.class::WEBHOOK_URL
options = self.class::DEFAULT_OPTIONS
#notifier = Slack::Notifier.new(webhook_url, options)
end
def self.send_message
message = instance.create_alert("test")
instance.notify(message)
end
def notify(message)
#notifier.post blocks: message
end
end
end
Add this to your spec_helper.rb
# spec_helper.rb
ENV["RAILS_ENV"] ||= "test"
require File.expand_path("../config/environment", __dir__)
When running RSpec, Rails doesn't automatically boot up, and therefore doesn't automatically load all the libraries.
Also, I'd suggest creating a .rspec in your app's root folder with the following lines so that spec_helper is automatically loaded for all your RSpec tests:
# .rspec
--format documentation
--color
--require spec_helper
I would use the described_class from Rspec
require 'spec_helper'
require 'slack-notifier'
RSpec.describe ::SlackService::BoardGameNotifier do
describe '#notify' do
it 'pings Slack' do
error = nil
message = "test"
expect(described_class).to receive(:ping).with(message)
notifier.send_message()
end
end
end

Rspec for ssh connection

I am trying to write rspec to test ssh connection. In my spec file even though I have enetered incorrect server password it still says 0 examples, 0 failures. Can someone exmplain me why am I seeing that whereas I am expected to see at least one failure message.
Below is the piece of code of my ssh_host.rb and ssh_host_spec.rb files.
require "java"
require "highline/import"
require 'open-uri'
require 'socket'
require 'rubygems'
require 'net/ssh'
require 'stringio'
require 'net/scp'
require 'colorize'
module SshMod
class SshHost
attr_accessor :hostname, :username, :password
def initialize(host, user, password)
#hostname = host
#username = user
#password = password
#ssh = Net::SSH.start(#hostname, #username, :password => #password)
puts "\t Connection established for #{#hostname}...".blue
end
end
end
Rspec Class:
#!/usr/bin/env rspec
require 'spec_helper'
require 'ssh_host.rb'
describe SshMod::SshHost do
before :each do
#ssh = SshMod::SshHost.new "servername", "user", "wrong_password"
end
end
describe "#new" do
it "takes three parameters and returns sshhostobject" do
#ssh.should_be_an_instance_of SshHost
end
end
ssh_mock = double()
expect(SSH).to receive(:start).and_return(ssh_mock)
There are a number of things wrong with your spec file. your test for new should be within the context of your SshMod::SshHost describe otherwise it doesn't have access to the ssh instance variable. Also, your code should throw some errors because except isn't defined in Kernel it's within the context of an Rspec object. You most likely want to put it in your before.
Regarding your requires in your ruby class, I'd get rid of everything that you don't need (for example, why the explicit inclusion of socket when using net-ssh?).
I believe however, that you're running into the issue where no tests are running most likely due to your project structure (but that's only a guess since you haven't listed it). Rspec by default looks for spec files listed under spec/**/*_spec.rb which you can override with the --pattern flag. See rspec --help for more info.
Here's a working example of your code with a bunch of things cleaned up. I put the source of your code in lib assuming you're making something like a gem.
Gemfile:
source "https://rubygems.org"
gem "colorize"
gem "rspec"
gem "net-ssh"
lib/ssh_host.rb
require 'net/ssh'
require 'colorize'
module SshMod
class SshHost
attr_accessor :hostname, :username, :password
def initialize(host, user, password)
#hostname = host
#username = user
#password = password
#ssh = Net::SSH.start(#hostname, #username, password: #password)
puts "\t Connection established for #{#hostname}...".blue
end
end
end
spec/spec_helper.rb
$:.unshift File.join(File.dirname(__FILE__), '..', 'lib')
require 'rspec'
RSpec.configure do |config|
config.mock_with :rspec do |mocks|
mocks.verify_partial_doubles = true
end
end
spec/ssh_host_spec.rb
require 'spec_helper'
require 'ssh_host'
describe SshMod::SshHost do
let (:ssh) { SshMod::SshHost.new "servername", "user", "wrong_password" }
before :each do
allow(Net::SSH).to receive(:start).and_return(double("connection"))
end
describe "#new" do
it "takes three parameters and returns sshhostobject" do
expect(ssh).to be_a SshMod::SshHost
end
end
end

Factory Girl: NameError: uninitialized constant Vserver

I am trying to setup the unit testing with Factory Girl and Rspec for my Sinatra application.
Gem file:
group :test do
gem "rack-test"
gem "fuubar"
gem "factory_girl"
gem "yard"
end
spec/factories/vserver.rb
require 'factory_girl'
FactoryGirl.define do
factory :vserver do
first_name "John"
last_name "Doe"
end
end
spec/spec_helper.rb
require File.join(File.dirname(__FILE__), "..", "app.rb")
%w{
rubygems
sinatra
dm-core
rack/test
uuid
factory_girl
rspec
pp
spec/factories/vserver
}.each { |r| require r }
set :environment, :test
# RSpec without Rails
RSpec.configure do |config|
config.include FactoryGirl::Syntax::Methods
end
spec/app_spec.rb
require './spec_helper.rb'
require 'factory_girl'
describe "Cdot" do
include Rack::Test::Methods
def app
StorageApi
end
it 'vserver' do
FactoryGirl.build(:vserver)
end
end
Issue: When I run the rspec file using the command: rspec app_spec.rb, I get the below error.
NameError: uninitialized constant Vserver
Help is much appreciated.
the code: factory :vserver do assumes that you have a class called Vserver that you are instantiating.
If you have such a class, then you need to include it in your spec.
If you don't have such a class, then you either need to rename the factory, or tell it what class it should be instantiating instead.

Why can't RSpec find the Airbrake env keys in a test involving Sidekiq when I specify environment?

Here is my setup:
airbrake.rb
require 'airbrake'
Airbrake.configure do |c|
c.ignore_environments = [:test, :development]
c.project_id = ENV['PROJECT_ID']
c.project_key = ENV['PROJECT_KEY']
end
use Airbrake::Rack::Middleware
spec_helper.rb
RSpec.configure do |config|
config.before(:suite) do
FactoryGirl.reload
FactoryGirl.define do
to_create { |instance| instance.save }
end
DatabaseCleaner.strategy = :transaction
DatabaseCleaner.clean_with(:truncation)
Airbrake.configure(:test) do |c|
c.project_id = ENV['PROJECT_ID']
c.project_key = ENV['PROJECT_KEY']
end
end
config.around(:each) do |example|
DatabaseCleaner.cleaning do
example.run
end
end
config.include FactoryGirl::Syntax::Methods
end
worker_test_spec.rb
require 'spec_helper'
RSpec.describe NotificationWorker do
it "perform should call Airbrake#notify" do
anotification_worker = LNotificationWorker.new
airbrake_notification_worker.perform("some error message"))
expect(Airbrake).to receive(:notify).with("some error message")
end
end
I call Airbrake#notify in other (non-Sidekiq) tests, and they find the appropriate ENV variables just fine.
Yet if I run the above Sidekiq test with the above setup, I get the following error:
Airbrake::Error:
the 'default' notifier isn't configured
But if I change the Airbrake config in spec_helper.rb to:
Airbrake.configure do |c|
c.project_id = ENV['PROJECT_ID']
c.project_key = ENV['PROJECT_KEY']
end
the ENV keys are able to be found in the tests. Why is this?
When you say Airbrake.configure(:test), it does not mean "configure Airbrake for the test RAILS_ENV". Rather :test creates a non-default named notifier. Then you can send specific notifications to that notifier by saying Airbrake.notify("oops", {time: Time.now}, :test). But that is not about development/test/production, it is about categorizing your notifications.
So the problem is that you have configured a notifier named test, but you have not yet configured one named default, and default is what Airbrake wants to use when you don't tell it otherwise. That's why your spec passes when you say simply Airbrake.configure { ... }.

Why am I getting FactoryGirl wrong number of arguments error?

Having strange behavior from FactoryGirl in non-rails app. getting wrong number of arguments error...don't know why.
gideon#thefonso ~/Sites/testing (master)$ rspec spec
/Users/gideon/.rvm/gems/ruby-1.9.3-p194/gems/factory_girl-4.1.0/lib/factory_girl/syntax/default.rb:6:in `define': wrong number of arguments (1 for 0) (ArgumentError)
from /Users/gideon/Sites/testing/spec/factories.rb:1:in `<top (required)>'
Here are the files involved...
login_user_spec.rb
require_relative '../spec_helper'
require_relative '../lib/login_user'
describe "Existing User Log in Scenario", :type => :request do
before :all do
#user = FactoryGirl(:user)
end
xit "should allow user to select login from top nav" do
visit "/"
within("#main-header")do
click_link 'Log In'
end
page.should have_content('Log in to your account')
end
it "and fill in login form" do
visit "/login"
within("#login-form")do
fill_in 'user-email', :with => #user.email
fill_in 'user-password', :with => #user.password
end
#FIXME - the design crew will make this go away
within("#login-form") do
click_link '#login-link' #this gives false failing test...geek query...why?
end
page.should have_content('Manage courses')
end
end
Factories.rb
FactoryGirl.define :user do |u|
u.email "joe#website.com"
u.password "joe009"
end
user.rb
class User
attr_accessor :email, :password
end
spec_helper.rb
require 'rubygems'
require 'bundler/setup'
require 'capybara'
require 'rspec'
require 'capybara/rspec'
require 'json'
require 'capybara/dsl'
# Capybara configuration
Capybara.default_driver = :selenium
Capybara.app_host = "http://www.website.com"
require 'factory_girl'
# give me ma stuff
FactoryGirl.find_definitions
require "rspec/expectations"
include Capybara::DSL
include RSpec::Matchers
ANSWER: :user is a reserved word..changed it to :stuff...works fine now.
Try to use new syntax from readme
FactoryGirl.define do
factory :user do
email "joe#website.com"
password "joe009"
end
end
If this is a non-rails app you will have to create a Userclass first. I'm not sure if you have to have instance vars with name, password and email but you definitely will have to have that class defined somewhere.
See the Getting Started file on Github for more on that.
Try this
FactoryGirl.define do
factory :user do |u|
u.email "joe#website.com"
u.password "joe009"
end
end

Resources