Should one unit test persistence in rails? - ruby-on-rails

We're doing a rails 3.2.1 project with RSpec 2. My question is, should i be testing the basic persistence of each of my activerecord models? I used to do this in my C# / NHibernate days, to ensure the correct tables/mappings were there.
So if i have a customer with name, address and phone fields, I might write an rspec like this:
describe Customer do
it "saves & retrieves its fields to and from the db"
c = Customer.new
c.name = "Bob Smith"
c.address = "123 some street"
c.phone = "555-555-5555"
or = Order.new
c.orders << or
c.save
found = Customer.find(c.id)
found.should_not be(c)
found.name.should == c.name
found.address.should == c.address
found.phone.should == c.phone
found.orders.count.should == 1
found.orders[0].id.should == or.id
end
end
Is this "best practice" or common in the ruby/rails/rspec world? I should also note that the point is not to test what rails is doing natively, but instead test that the correct fields and relationships are setup in the db and models.

No. You shouldn't be unit testing the persistence. A unit test validates the unit works in isolation, and you should only test your code. The persistence functionality is a part of Rails, and since it is not your code, you shouldn't write unit tests for it.
You could be interested in testing the mappings, but not in a unit test. You would write an integration test for that. An integration test would test your module, integrating with another part of the system, perhaps all the way to the database. Running those tests would validate that your module works with the database, i.e. the mappings are good.
In short - you don't test persistence in unit tests; you test them in integration tests.

No, I don't believe it is a best practice to do this sort of lower level testing as the majority of these tests would be built into to the testing for Rails and the ORM you are using.
However, if you are overriding any methods or performing complex association logic in your models it'd be best to have your own tests.

Related

Rails testing models

I'd like to test models working with each other. Something like this:
query = Query.new
user = users(:first)
assert_equal Query::STATUSES[:new], query.status
query.resend_to user.id
asser_equal Query::STATUSES[:resent], query.status
asser_equal 1, user.queries.size
But I even dont know, what is the right name for such kind of testing, scenario driven testing, behaviour driven testing?
Please, tell me how it's called and some examples.

Rails3 - Testing - what is the relationship errors and invalid?

In the following code, do the errors support invalid?
in other words is invalid? true or contingent upon the list of errors being true
or is invalid? working on its own?
test "product attributes must not be empty" do product = Product.new
assert product.invalid? assert product.errors[:title].any?
assert product.errors[:description].any?
assert product.errors[:price].any?
assert product.errors[:image_url].any?
end
Also, may I assume that:
Functional Testing (for controllers) perform at run time for the user,
while Unit Testing (for Models / Database) are for use during development
THANKS!strong text
The tests are run during development, to try and ensure the code you produce is as error-free as possible.
Unit tests check small units of code (e.g. a single model), while functional tests check "functions" that take several steps (such as the "signing" up process).
The valid? function essentially makes the model go through the defined validators, and checks whether there where errors. In other words, if the #user.errors array (for example) contains entires, valid? will return false.
But once again, tests are used to check you're developing your code properly, and will NOT run in production.

What's the difference between mock, stub, and factory girl?

I'm pretty new to rspec and the whole TDD methodology. Can someone please explain the difference between mock and stub. When do we use them and when do we use Factory Girl to create objects in test cases?
You could think of a mock (or double) as a fake object. When you're testing and need to work with an object that isn't easily usable inside your test, you could use a mock as an approximation for how you expect that object to behave and work around it. Stubs can be used in a similar manner but on an individual method on an object.
Here's a rather contrived example of using a lot of both:
class Client
def connect_to_server
if Server.connect.status == 'bad'
show_an_error
else
do_something_else
end
end
def do_something_else; end
def show_an_error; end
end
context "failure" do
it "displays an error" do
bad_network_response = double("A bad response from some service", :status => 'bad')
Server.should_receive(:connect).and_return(bad_network_response)
client = Client.new
client.should_receive(:show_an_error)
client.connect_to_server
end
end
You can imagine that using a lot of mocks or stubbing is a bad idea; this is basically masking out parts of your code in your test but, it's an easy solution for some difficult/rare testing scenarios.
Factory Girl is useful for generating data for tests. You would use factories as recipes for creating instances for your models, you might need to test something involving a lot of test data and this would be a situation where using fixtures won't work and creating complicated objects explicitly can be tedious.
Your first stop is Martin Fowler's famous article : Mocks are not Stubs
Edit
Mocks and Stubs are two of the types of Test Doubles (Mezaros terminology). Test doubles are typically used to simulate the dependencies needed by a System Under Test (or Class Under Test), so that the SUT / CUT may be tested in isolation from its dependencies. (Caveat - precise terminology can be quite a touchy subject e.g. as mentioned by Jeff here)
From wikipedia:
"Test stubs provide canned answers"
"mock objects can simulate the behavior of complex, real objects"
Examples
A stub method may just return a constant value when called by the SUT, e.g. for conducting a specific test case of the SUT.
*Frameworks like Mockito (Java) and Moq (.Net) allow you to build mock classes against a dependency's interface on the fly with a minimum of code, and provide the ability to verify that the SUT interacted correctly with the mock, e.g. by checking that the SUT invoked the mock's methods the correct number of times, with the correct parameters.
* Disclaimer - I'm not a ruby dev

running Rails unit tests without loading the environment or using a database

As something of an academic exercise, I thought I'd try to get my unit tests running without loading the Rails env (or hitting the database).
I've seen this done before, and it seems like folks talk about it enough, but I can't find any good/current resources on getting it done.
Does anyone have any good stories or a nice long blog post about how to do this?
An useful link: testing Rails without Rails
Testing without database would involve much mocks & stubs, nothing special to add.
Check out NullDB. I've had mixed success with it.
The creator & current maintainer are looking to get a new maintainer in so some of its current issues should be ironed out soon.
Alternative approach to write application little bit differently.
Extract all important logic you want to test into ruby classes without database dependencies.
Write tests for those classes only - your tests will fly! :)
For example
ProductQuantity = Struct.new(:product_id, :quantity)
class Customer < ActiveRecord
def create_order(product_quantities)
product_ids = product_quantities.map(&:product_id)
products = Product.where(:id => product_ids).pluck(:id, unit_price).to_h
total = product_quantities.reduce(0) do |sum, p|
sum += p.quantity * products.fetch(p.product_id, 0)
end
Order.create!(:customer_id => id, :total => total)
end
end
Extract "business logic" out of database dependencies
class Customer < ActiveRecord
def create_order(product_quantities)
products = Product.where(:id => product_ids).pluck(:id, unit_price).to_h
total = CalculateNewOrderTotal.from(products, product_quantities)
Order.create!(:customer_id => id, :total => total)
end
end
module CalculateNewOrderTotal
def self.from(products, product_quantities)
product_quantities.reduce(0) do |sum, p|
sum += p.quantity * products.fetch(p.product_id, 0)
end
end
end
Now the module CalculateNewOrderTotal can be fully covered with very fast tests which doesn't require mocks or actual database.
You can still write happy path tests with actual database for Customer.create_order method.
Extra benefits
Your business logic is independent of persistence framework.
Your business logic is independent of persistence schema, you can change how to store data without "touching" important business logic code.
No mocks involved
No extra layers of abstractions - you can still use all benefits of the ActiveRecord, for example wrap call of the method with the transaction.
No other frameworks or gems are involved - pure ruby and RSpec or testing framework of your choice :)

How can I check Rails record caching in unit tests?

I'm trying to make a unit test to ensure that certain operations do / do not query the database. Is there some way I can watch for queries, or some counter I can check at the very worst?
If your intent is to discern whether or not Rails (ActiveRecord) actually caches queries, you don't have to write a unit test for those - they already exist and are part of Rails itself.
Edit:
In that case, I would probably see if I could adapt one of the strategies the rails team uses to test ActiveRecord itself. Check the following test from my link above:
def test_middleware_caches
mw = ActiveRecord::QueryCache.new lambda { |env|
Task.find 1
Task.find 1
assert_equal 1, ActiveRecord::Base.connection.query_cache.length
}
mw.call({})
end
You may be able to do something like the following:
def check_number_of_queries
mw = ActiveRecord::QueryCache.new lambda { |env|
# Assuming this object is set up to perform all its operations already
MyObject.first.do_something_and_perform_side_operations
puts ActiveRecord::Base.connection.query_cache.length.to_s
}
end
I haven't tried such a thing, but it might be worth investigating further. If the above actually does return the number of cached queries waiting to happen, it should be trivial to change the puts to an assert for your test case.

Resources