Ruby on Rails Test Database Not Committing New Records - ruby-on-rails

Is there a way to use Factory Girl to commit new changes to the test database in Ruby on Rails?
I have the following factory:
Factory.define :shipping_info do |si|
si.name "Foo Bar"
si.street "12 Candy Lane"
si.country "US"
si.zip "12345"
si.state "IL"
end
And I have the the following test:
require File.dirname(__FILE__) + '/../../spec_helper'
describe CgCart::ShippingInfo do
before(:each) do
#order = Factory(:order)
#order.order_line_item = Factory(:order_line_item)
#shipping_info = Factory(:shipping_info)
end
it "order should not be nil" do
#shipping_info.should_not be_nil
end
end
When I run this test it passes. However, no new records are created in my test database. I need data in there for a Dameon to work with.
Any suggestions?

Using Factory.create(:order) should write that object to your database.
If you have transactional fixture set to true, all data that gets written to database gets rolled back after the tests finish.
You cant tail -f log/test.log before running your tests and you will see a lot of activity there.
I hope that clears your situation.

Related

why factoryGirl don't rollback after build and save in rspec

I don't understand why my record in 2 spec is not rollback:
I have 2 tables, prefecture has_many hospitals
require "rails_helper"
RSpec.describe Hospital, type: :model, focus: true do
context "created along with new hospital created" do
it "should create new hospital" do
#prefecture = FactoryGirl.create(:prefecture)
hospital = FactoryGirl.build(:hospital, id: 10, prefecture: #prefecture)
expect { hospital.save }.to change { Hospital.count }.by 1
end
it "should save" do
#prefecture = FactoryGirl.create(:prefecture)
hospital = FactoryGirl.build(:hospital, id: 10, prefecture: #prefecture)
hospital.save
end
end
end
If I run it will show error "id=10 is existed in db"
Can anyone explain where I am mistake?
Thank you.
It is not the responsibility of FactoryGirl. You have 2 options:
Use transactions in tests: https://relishapp.com/rspec/rspec-rails/docs/transactions
Use a gem which cleans DB after after test such as: https://github.com/DatabaseCleaner/database_cleaner
Usually your models test will use transctions and database cleaner is used for integration/acceptance tests which cannot operate within transaction because a separate process (browser) needs to read the data created in tests.
By default, the rspec will not reset your database for each test. You need to configure it. Is because that your second test is falling, already exists a Hospital with id = 10.
When you remove the parameter id for the second test and runs with success, FactoryGirl will generate automatically a new id.
The method build from FactoryGirl will not fill the attribute id, just the rest of the attributes. Is because that when you call save after build method, the FactoryGirll generate a new id and your tests pass successfully.
after :build do |offer|
offer.save
end

Rspec Running Tests Results in Validation Errors

For example:
I run a test and all asserts pass, but I run the test again, and in my case, I receive the following error:
Validation failed: Email has already been taken
It seems adding: sequence(:email) {|n| "nobody#{n}#xyz.com" } for factorygirl is pointless
The tests seem to pass sometimes and others fail for errors reasons like these.
Please advise on the problem/solution.
try deleting all the records from tables before running test case.
eg:-
describe User do
before(:each) do
User.delete_all
end
it "validate e-mail" do
(do staff..)
end
end
I´m not sure it is a definitive solution, but i added random numbers to my product references on the factories with factorygirl using the lazy attributes.
Example:
FactoryGirl.define do
factory :product do
reference {"AB"+rand(999).to_s}
description "Test Product"
quantity {(1..9999).to_a.sample}
price_per_unit {((1..999999).to_a.sample)/100.to_f}
end
end
Do you have any "before(:all)" block? maybe you are missing the corresponding "after(:all)" to clean the data. before(:each) acts as a transaction so the database gets cleaned, before(:all) works like a normal query, yout have to handle the cleanup in an after(:all) block.

avoid factorygirl repeate the number when run second time in cucumber

Its my factorygirl code
FactoryGirl.define do
factory :account do
sequence :name do |n|
"Test Account#{n}"
end
end
end
This is my method for run factorygirl code
def create_accounts n=2
n.times do
FactoryGirl.create(:account, subscription_ids: #sub.id.to_s)
end
end
My problem is, first time my FactoryGirl output is Test Account1, Test Account2, When i execute second time, It create output as Test Account3, Test Account4. But I need Test Account1, Test Account2 when run multiple time. How may i do this.
Thanks for your advices
FactoryGirl is designed to create new unique records every time you call #create. If you want to keep the original record set around, you should save them to a variable and then return them rather than running FactoryGirl.create again.
You can also use database_cleaner gem to clean the database after every test. This helps to prevent any problems rising from the state of the database.
I solve this problem after replace this code
def create_accounts n=1
create_subscription
n.times do |r|
r += 1
FactoryGirl.create(:account, subscription_ids: #sub.id.to_s, name: "Test Account#{r}")
end
end
Updated
I am using cucumber-> capybara -> selenium
Reset the factory girl sequence
add this code in spec->support->reset.rb
module FactoryGirl
def self.reload
self.factories.clear
self.sequences.clear
self.traits.clear
self.find_definitions
end
end
Add this in env.rb
After do
FactoryGirl.reload
end

Rails 3 + DataMapper - database not created/destroyed between tests

I'll try here since the mailing list for DM doesn't seem to have much input from other users unfortunately.
I'm reasonably sure this isn't something we have to do manually, but maybe I'm wrong. I've removed ActiveRecord from my project and have started creating models in DataMapper. It's all working, but I want to write unit tests for my models (and functional for my controllers). However, my test database is not cleaned between test runs (easily proven with a test). AR takes care of this for you, but it seems like the DM guys haven't considered this in their dm-rails project.
In a desperate attempt to wipe the slate clean, I dropped all tables in my test database. Now instead of my unit tests failing because the environment is dirty, they fail because the schema doesn't exist. Looking at the rake tasks available to me, I cannot restore my test DB without also wiping my development database. I'm starting to go insane and hoping a fellow DM + Rails 3 user can nudge me in the right direction.
Specifically, when I run my unit tests, all test data should be removed between the test methods. Also, if I make a change to the schema, I should be able to run my tests and they should work.
I tried putting DataMapper.auto_migrate! in a setup callback in my test_helper.rb, but this doesn't seem to create the schema (the tests still fail due to the tables not existing when they try to insert/select records).
I've seen https://github.com/bmabey/database_cleaner, but do we really have to bring an external library into Rails just to do something that DM probably already has (seemingly undocumented) support for? This also doesn't address the issue of recreating the schema.
The answer came back on the mailing list that it's basically a do-it-yourself situation, so to save others the hassle if they end up having to do this too:
Create a .rake file under lib/tasks, called something like test_db_setup.rake:
require File.dirname(__FILE__) + '/../../test/database_dumper'
# Custom logic that runs before the test suite begins
# This just clones the development database schema to the test database
# Note that each test does a lightweight teardown of just truncating all tables
namespace :db do
namespace :test do
desc "Reset the test database to match the development schema"
task :prepare do
Rake::Task['db:schema:clone'].invoke
end
end
namespace :schema do
desc "Literally dump the database schema into db/schema/**/*.sql"
task :dump => :environment do
DatabaseDumper.dump_schema(:directory => "#{Rails.root}/db/schema", :env => Rails.env)
end
desc "Clones the development schema into the test database"
task :clone => [:dump, :environment] do
DatabaseDumper.import_schema(:directory => "#{Rails.root}/db/schema", :env => "test")
end
end
end
task 'test:prepare' => 'db:test:prepare'
This uses the :test:prepare hook that Rails provides, which runs just before the test suite begins. It copies the schema from your development database into .sql files under db/schema/ (one per table/view), then it imports those .sql files into your test database.
You'll need the utility class I wrote for this to work (currently it's written for MySQL >= 5.0.1. You'll have to adjust the logic if you need a different database.
# Utility class for dumping and importing the database schema
class DatabaseDumper
def self.dump_schema(options = {})
options[:directory] ||= "#{Rails.root}/db/schema"
options[:env] ||= Rails.env
schema_dir = options[:directory]
clean_sql_directory(schema_dir)
Rails::DataMapper.configuration.repositories[options[:env]].each do |repository, config|
repository_dir = "#{schema_dir}/#{repository}"
adapter = DataMapper.setup(repository, config)
perform_schema_dump(adapter, repository_dir)
end
end
def self.import_schema(options = {})
options[:directory] ||= "#{Rails.root}/db/schema"
options[:env] ||= "test"
schema_dir = options[:directory]
Rails::DataMapper.configuration.repositories[options[:env]].each do |repository, config|
repository_dir = "#{schema_dir}/#{repository}"
adapter = DataMapper.setup(repository, config)
perform_schema_import(adapter, repository_dir)
end
end
private
def self.clean_sql_directory(path)
Dir.mkdir(path) unless Dir.exists?(path)
Dir.glob("#{path}/**/*.sql").each do |file|
File.delete(file)
end
end
def self.perform_schema_dump(adapter, path)
Dir.mkdir(path) unless Dir.exists?(path)
adapter.select("SHOW FULL TABLES").each do |row|
name = row.values.first
type = row.values.last
sql_dir = "#{path}/#{directory_name_for_table_type(type)}"
Dir.mkdir(sql_dir) unless Dir.exists?(sql_dir)
schema_info = adapter.select("SHOW CREATE TABLE #{name}").first
sql = schema_info.values.last
f = File.open("#{sql_dir}/#{name}.sql", "w+")
f << sql << "\n"
f.close
end
end
def self.directory_name_for_table_type(type)
case type
when "VIEW"
"views"
when "BASE TABLE"
"tables"
else
raise "Unknown table type #{type}"
end
end
def self.perform_schema_import(adapter, path)
tables_dir = "#{path}/tables"
views_dir = "#{path}/views"
{ "TABLE" => tables_dir, "VIEW" => views_dir }.each do |type, sql_dir|
Dir.glob("#{sql_dir}/*.sql").each do |file|
name = File.basename(file, ".sql")
drop_sql = "DROP #{type} IF EXISTS `#{name}`"
create_sql = File.open(file, "r").read
adapter.execute(drop_sql)
adapter.execute(create_sql)
end
end
end
end
This will also leave the .sql files in your schema directory, so you can browse them if you want a reference.
Now this will only wipe your database (by installing a fresh schema) as the test suite starts up. It won't wipe the tests between test methods. For that you'll want to use DatabaseCleaner. Put it in your test_helper.rb:
require 'database_cleaner'
DatabaseCleaner.strategy = :truncation, {:except => %w(auctionindexview helpindexview)}
class ActiveSupport::TestCase
setup :setup_database
teardown :clean_database
private
def setup_database
DatabaseCleaner.start
end
def clean_database
DatabaseCleaner.clean
end
end
Now you should be good to go. Your schema will be fresh when you start running the tests, you'll have a copy of your SQL in the db/schema directory, and your data will be wiped between test methods. A word of warning if you're enticed by the transaction strategy of DatabaseCleaner... this is rarely a safe strategy to use in MySQL, since none of the MySQL table types currently support nested transactions, so your application logic will likely break the teardown. Truncate is still fast, and much safer.

Rails Controller testing: Does database state change persist after success of test?

I am testing create method of BranchController using ActionController::TestCase (code below) . I check if object is created by calling find_by_name method(assume name is unique here).
test runs succesfully but when i check same record in mysql db, its not there.
class Security::BranchControllerTest < ActionController::TestCase
test "the create" do
post(:create, :branch => {:name => "test branch", :details=> "test branch details"})
#replace find with where searching with all of fields
assert_not_nil Company::Branch.find_by_name("test branch")
end
end
If you're using a database that supports transactions (as most do these days), rails tests will by default set a savepoint before running each test and do a rollback at the end.
This means that the insertion is actually happening, but the result is not visible outside the test.
You should see the savepoint and rollback operations in your test logs.
If you want to disable this, you can add
self.use_transactional_fixtures = false
in your test class, or patch it in for all your tests by adding something like
class ActiveSupport::TestCase
self.use_transactional_fixtures = false
end
in your test_helper class.
It's likely not a good idea to disable this generally though, as it's a nice way to keep your tests independent.

Resources