Rails 5.1 System Test Fixtures and Database Cleanup - ruby-on-rails

Are rails 5.1 system tests supposed to reset the test database with original fixture data between each test?
This is not happening for me even between completely different test classes. One of my system tests is:
test 'delete thing' do
# deletes a thing from the fixture data
end
then I have another test that just looks to see if the thing is there
test 'view thing' do
# tries to view the thing
end
The test passes if the "view thing" test is ran first. If the "delete thing" test runs first then when my system test tries to view the thing then it fails.
I thought Rails system tests were resetting the data just like all the other tests. Is this not the case? Am I missing something?

Solved this one by changing the number of workers in our config/puma.rb file to 0 instead of 1.
Changing
workers ENV.fetch("WEB_CONCURRENCY") { 1 }
to
workers ENV.fetch("WEB_CONCURRENCY") { 0 }
fixed the issue for us.

I have just been dealing with this exact issue this morning, and I think I have figured it out.
This doc on fixtures helped me a bit: http://api.rubyonrails.org/v5.1.4/classes/ActiveRecord/FixtureSet.html.
For me though, I just had to make sure i was using the ModelName.method approach when my test involved modifying data (like adding and deleting records) as this interacts with the test database and does not change your fixtures. At first I was using the fixture_name.method for both reading and writing, and that led to unexpected results.
So for example, with a model of Blog and a fixture file blogs.yml with one record in it (hashed to key = :one):
test "view blog" do
get blog_path blogs(:one).id
assert_response :success
*OR*
get blog_path Blog.first.id
assert_response :success
end
But if modifying, stick with the second approach:
test "delete blogs" do
assert_equal 1, Blog.count
assert_equal Blog.first.id, blogs(:one).id
Blog.destroy_all
assert_equal 0, Blog.count
assert_raises(NoMethodError) { Blog.first.id }
assert_nothing_raised { blogs(:one).id }
end
test "before_or_after_delete_blogs" do
assert_equal 1, Blog.count
assert_equal Blog.first.id, blogs(:one).id
end
Both of those should pass.
Apologies if my explanation is off base. If that's the case, could you provide a little more context with your example?

I use the gem database_cleaner. Not sure if that's exactly the answer to your problem.
Also this could help?
rake db:test:prepare
Not too sure if your issue but hopefully that helps

Related

Rails + RSpec + Set the Order of Test Cases Files while running RSpec Test Suite

For RSpec Capybara Test Case [ Selenium ], I have near about 7 to 8 spec files. Few of the test cases are dependent on each other. For example, before deleting an product, I have to create the product.
But when test cases excution starts, delete product based rspec runs before the create product rspec.
File Name:-
product_delete.rspec
product_listing.rspec
product_newly_added.rspec
Command : rspec
.rspec file in root folder
--require spec_helper
--format html
--out ./log/rspec_results.html
--color
Test case failed while execution for delete product.
Is there any way to define the sequence of file execution while running RSpec.
Test cases should be independent. For your delete test case you can use factory and create a record then delete it in a single test case as shown in example.
just define factory once and use it to create records, in this way DRY wont be violated.
describe 'POST destroy' do
before(:each) do
#obj = build(:factory_name)
#obj.save
end
it 'it has status 200' do
post :destroy, {"id" => #obj.id}
expect(ClassOfObj.count).to eq(0)
end
end
One possible approach is to not separate these actions into their own test cases. With feature specs you test whole features, not single buttons. So, your test might look like this:
Navigate to new item page. Make sure form is displayed
Fill out the form. Click submit. Verify that success message is displayed on screen.
Verify that you have been redirected to item index page. Verify that newly created item is indeed present on the page.
Click "delete" button.
Confirm that you're on index page and that item is no longer displayed.
As mentioned by most/all the other answers, your tests should be independent, and RSpec supports running tests in random order to guarantee that. One of the easiest ways to implement testing in these conditions is to use factories for the creation of your test data (FactorGirl, etc). In this case you would end up with a test along the lines of
feature "deleting of products" do
scenario "removes last product" do
create(:product) # Use factory to create one product
visit products_path
expect(page).to have_css('div.product', count: 1) # verify there is only one product shown on the page
click_link('delete') # click the delete button
expect(page).to have_text("Product deleted!") # check for a visible change that indicates deletion has completed
visit products_path
expect(page).not_to have_css('div.product') # No products shown any more - you may need to expect for something else first if the products are dynamically loaded to the page to ensure that has completed
end
end
You could check the DB contents rather than revisiting the products_path, but direct DB querying in feature tests is generally a bad smell since it's coupling user experience with implementation details.
If using this in Rails < 5.1 with a JS capable driver, you'll probably need to install database_cleaner and turn off transaction mode for JS tests - https://github.com/teamcapybara/capybara#transactions-and-database-setup and https://github.com/DatabaseCleaner/database_cleaner#rspec-with-capybara-example. In Rails 5.1+ the DB connection is shared between the app and tests so you can generally leave transactional testing enabled and database_cleaner is unneeded.

RSpec get around unique requirement in testing

My Signup database has an index on email with a unique requirement. This is great, but the problem is that I'm trying to run integration tests, and every time I go rake rspec spec/features/...rb, unless I did rake db:test:purge, rake db:test:prepare first, it runs into the unique problem and refuses to run. How do I streamline this?
From the code below, you can see that every time I'm running the test, I'm creating a set of seed data with my before(:all), but since the seed data is always the same, this is driving the uniqueness error.
I'm happy to just put this seed data elsewhere or create it some other way, as long as my test suite is still able to run using this seed data.
describe "how requests should flow" do
before(:all) do
#signup_dd = Signup.create(email:"example#example.com")
end
it "should have 2 inventories and 2 signups to start" do
Signup.count.should == 1
end
describe "request creation" do
before do
Signup.find_by_id(#signup_dd)
visit '/requests/new'
save_and_open_page
fill_in '#borrow__1', :with => 1
click_button
end
it "should affect new Requests and Borrows" do
...
end
end
end
There are two ways to fix this:
Remove the (:all) from the before block. RSpec will execute the before block for each test. It will then undo itself after each test. This is really what you want as it ensures changes made by each test do not bleed into other tests. This is usually the recommended approach.
Keep the (:all), but then add a (:after) block to undo your changes. With the :all argument, the before block is only executed once instead of every time. However, it doesn't automatically undo itself like :each, so the :after block becomes necessary. It is up to you, however, to figure out what needs to go in there. In your example, for instance, it might be:
after(:all) do
Signup.delete_all # Or whatever undoes what the before block did
end
See this blog post regarding the use of the two techniques.
when you use before(:all), you need use after(:all) to clean up the data you created in before(:all)

What is happening during Rails Testing?

I'm new to Ruby On Rails. I love, it has Testing capabilities built in. But, I can't wrap around my head with testing. Here is my first basic Question about it.
What happens during testing really?
I understand development, we want some result, we use the data we have or get it from users to achieve the end result we want. But, the notion of testing seems sometimes confusing for me. I have been testing applications in browser for some time, are we replicating the same with code? Is it what testing is about? Replicating browser testing with automated code? Enlighten Me here.
Reading A Guide to Testing Rails Applications will be a good starting point.
Basically, you have three kinds of tests: unit, functional and integration.
Unit tests are testing your Models. In these tests you check whether a single method of your model works as expected, for example you set assign a login with spaces, and then you test whether the spaces were removed:
class UserTest < ActiveSupport::TestCase
def test_login_cleaning
u = User.new
u.login = " login_with_spaces "
assert_equal "login_with_spaces", u.login
end
# ... and other tests
end
Functional tests are testing your controllers (and views). In each test you simulate one request sent to one controller with given set of parameters, and then you ensure that the controller returned the proper response.
Note however, that in this test you cannot test the rendering of the page, so it's not strictly simulating a browser. To test whether your page looks nicely, you need to do it manually (I am almost sure some techniques exist, but I do not know of them).
An example of functional test:
class UserControllerTest < ActionController::TestCase
def test_show_renders_admin
get :show, :id => 1
assert_response :success
assert_select "div.user" do
assert_select "span.name", "Joe Admin"
end
end
def test_show_handles_unknown_id
get :show, :id => 9999
assert_response 404
assert_select "p.warning", "No such user"
end
end
Integration tests are testing a sequence of requests - something like a scenario, where an user logins, gets the 'create user' page, creates an user, and so on. These tests check whether the single requests (tested in functional tests) are able to work together.
I see that Simone already pointed the importance of automation in tests, so the link to the Guide is the only value in my answer ;-)
You may find it very helpful to apply some rules of Test Driven Development, especially when your project matures a little.
I know that it's not easy to start the project by writing test, because often you do not yet know how everything will work, but later, when you find a bug, I strongly suggest to start fixing every bug from writing a failing test case. It really, really helps both in the bug-fixing phase, and later - ensuring that the bug does not reappear.
Well, I noticed that I did not directly answer your question ;-)
When you start test procedure, Rails:
deletes the test database (so make sure you do not have any valuable data here),
recreates it using the structure of the development database (so, make sure you have run all your migrations),
loads all the fixtures (from test/fixtures/*)
loads all the test classes from test/units/* and other directories,
calls every method whose name starts with 'test_' or was created by the macro test "should something.." (alphabetically, but you may consider the order as being random)
before every call it executes a special setup procedure, and after every call it executes teardown procedure,
before every call it may (depending on the configuration) recreate your database data, loading the fixtures again.
You will find more information in the Guide.
What happens during testing is that you really run a set of specialized programs or routines (test code) that calls routines in your application (code under test) and verifies that they produce the expected results. The testing framework usually has some mechanism to make sure that each test routine is independent of the other tests. In other words the result from one test does not affect the result of the others.
In Rails specifically you run the tests using the rake test command line tool. This will load and execute each test routine in a random order, and tell you if each test was successful or not.
This answer doesn't necessary apply to Rails itself. When you talk about testing in Rails, you usually mean automatic testing.
The word automatic is the essence of the meaning. This is in fact the biggest difference between unit testing and "browser" testing.
With unit testing you essentially write a code, a routine, that stresses a specific portion of your code to make sure it works as expected. The main advantages of unit testing compared to "browser" testing are:
It's automatic and can be run programmatically.
Your test suite increases during the development lifecycle.
You reduce the risk of regression bugs, because when you modify a piece of code and you run the test suite, you are actually running all the tests, not just a random check.
Here's a basic, very simple example. Take a model, let's say the User model. You have the following attributes: first_name, last_name. You want a method called name to return the first and last name, if they exist.
Here's the method
class User
def name
[first_name, last_name].reject(&:blank?).join(" ")
end
end
and here's the corresponding unit test.
require 'test_helper'
class UserTest < ActiveSupport::TestCase
def test_name
assert_equal "John Doe", User.new(:first_name => "John", :last_name => "Doe").name
assert_equal "John", User.new(:first_name => "John").name
assert_equal "Doe", User.new(:last_name => "Doe").name
assert_equal "", User.new().name
end
end

factory_girl + rspec doesn't seem to roll back changes after each example

Similar to the problem described here:
http://rpheath.com/posts/411-how-to-use-factory-girl-with-rspec
in Short (shorten'd code):
spec_helper:
config.use_transactional_fixtures = true
config.use_instantiated_fixtures = false
factories.rb:
Factory.define :state do
f.name "NY"
end
in my spec
before(:each) do
#static_model = Factory(:state) # with validate uniqueness of state name
end
error:
duplicate entry name "NY" etc.
Question:
Shouldn't rspec clear database before each spec example and hence not throwing duplicate entry errors?
Things i think off:
do you use rake spec to run your testsuite: that builds up the database from scratch (to make sure nothing is sticking)
do you use, anywhere, a before (:all) ? Because whatever you create inside a before :all should be deleted again in a after :all or it keeps on existing.
Question: Shouldn't rspec clear database before each spec example and hence not throwing duplicate entry errors?
RSpec with DatabaseCleaner or RSpec Rails with use_transactional_fixtures will clear the DB as long as your created the data in the example itself. before :all do ... end is considered outside of the example, because the data remains untouched across multiple examples. Whatever you create in before :all you have to delete in after :all.
In order to delete whatever you create automatically use before :each do ... end. Be aware the same data will be created and removed 10 times if you have 10 examples. The difference between before :all and before :each is better explained here: rails rspec before all vs before each
Some more possible causes:
There's still a states.yml fixture sitting around
Someone played around on script/console test and forgot to clean up afterwards.
You might also find it's because you haven't wrapped the statement in:
describe "what it should do" do
#static_model = Factory(:state) # with validate uniqueness of state name
end
I discovered that was the change that solved this problem:
Why isn't factory_girl operating transactionally for me? - rows remain in database after tests
I have had similar questions about what sort of starting state one can expect when using FG and RSpec.
While I too wait for clarity, Database Cleaner could be a good fix: http://rubydoc.info/gems/database_cleaner/0.6.7/frames
hth -
Perry
When you use Factory(:state) wich is a shortcut to Factory.create(:state), factory_girl returns you a saved object.
Use Factory.build(:state) instead.
Dude maybe your yaml fixtures from regular unit tests get mixed into your rspec?

Why are my functional tests failing?

I have generated some scaffolding for my rails app.
I am running the generated tests and they are failing.
for example
test "should create area" do
assert_difference('Area.count') do
post :create, :area => { :name => 'area1' }
end
assert_redirected_to area_path(assigns(:area))
end
This test is failing saying that :
1) Failure:
test_should_create_area(AreasControllerTest)
[/test/functional/areas_controller_test.rb:16]:
"Area.count" didn't change by 1. <3>
expected but was <2>.
There is only one field in the model : name. I am populating this so it cant be because I am failing to populate the only field.
I can run the site and create an area with the name 'area1'. So reality is succeeding, but the test is failing.
I cant ask why its failing, because Im sure theres not enough information here for anyone here to know why. Im just stuck at knowing what avenues to go down to work out why the test is failing. Even putting puts into the code dont print out...
What steps can I take to track this down?
Per the request above, and matching what I was expecting that you'd find when you dug into your logs, you have an authorization that isn't being met in your test.
#request and #response are also useful objects to look at (i.e. puts #response inside your test). I don't know what authentication you are using, but check RAILS_ROOT/lib for authenticated_test_helper, or the /lib, or /test of your authentication gem. You'll find methods for performing a login.

Resources