I've got a document management system which I programmed in Rails 2.3.8 a while ago and I've been retrofitting some rspec tests to the project before refactoring and making enhancements.
The problem is a lot of my tests require stubbing out most of the File & FileUtils libraries as there is a lot of file interaction within models. Is there a better way to test File & Directory actions without having to touch the filesystem at all?
For instance I stub out mkdir_p:
FileUtils.stub!(:mkdir_p)
And when I'm moving I use something like this:
FileUtils.should_receive(:mv).with("from path","to path")
Use fakefs. It's perfect for the purpose.
I would not recommend to alter File or FileUtils classes, because these changes will affect all your running unit tests. It will be hard to track these changes when you have a lot of different tests and your tests will start affecting each other (which is generally bad testing practice).
I propose to explicitly use a simple manual Dependency Injection approach like constructor injection:
class UnderTest
def initialize file_creator = FileUtils
#file_creator = file_creator
end
def use_file_utils
#file_creator.mkdir('some_dir')
end
end
In RSpec test:
fake_file_utils = mock "FileUtils"
test = UnderTest.new fake_file_utils
test.use_file_utils
Related
I'm currently working on a project and we started migrating our tests to isolated test (no rails dependency, and using stubs and mocks).
The thing is that until all the current tests are being isolated, we have to run the tests together with the isolated tests, which will start the rails environment.
The problem comes when, in the isolated tests, there is a fake class (class Foo; end;), it will override the original class for the rest of the tests.
Example:
In the foo_spec.rb we have this line
class Bar; end;
This would override the Bar class for the next nonisolated tests, and would cause a lot of fails.
There are 2 approaches I could figure in order to get rid of this:
- either comment out the fake classes when the tests are run with rails env
- put the isolated tests in another folder and run them separated from the rest (this would make more sense)
Can you think of a nicer way to deal with this?
we are using rspec (which should not change anything) and have our rails spec located in spec with their own spec_helper.rb file that is loading the env and all the ugly stuff.
in spec_fast folder we have all the spec that can run without rails, with their own spec-helper that only loads our independent lib folder.
for our ci-server we let both spec folder run in a different task:
if Rails.env.test?
require 'rspec/core/rake_task'
require 'ci/reporter/rake/rspec'
RSpec::Core::RakeTask.new(:all_fast) do |t|
t.pattern = 'spec_fast/**/*_spec.rb'
end
RSpec::Core::RakeTask.new(:all_slow) do |t|
t.pattern = 'spec/**/*_spec.rb'
end
task :all => ["ci:setup:rspec", :all_fast, :all_slow]
end
it should also be possible to just put them into separate subfolders like spec/rails and spec/fast but i did not try it out because it means to do a lot of path-changing in spec-files.
I don't know if it's right, but I end up not actually assigning such contextual dummy manually created dummy classes to constants.
Instead of:
#no
class Foo
#something
end
Instead:
foo = Class.new do
#stuff
end
And you can foo.new or foo.class_method to your heart's content. Could be in #foo too. But you aren't assigning it to the constant Foo like ordinary class definition does, you're creating an 'anonymous' class and assigning it to an ordinary variable, scoped to just within the area you need it.
Note: I'm not saying this is "right" way to do things with rspec, I never feel like I know the right thing to do, the right thing to do might be to somehow not create classes like this at all, or use some weird factorygirl thing which I don't understand or something. But when I need to create 'dummy' type classes just to the scope of a particular test or block, that's what I do.
Using Rails 3.0, I have a small bit of code that I seem to be calling in all my Unit tests.
Is there a common place to put shared unit test code that won't be incorporated into both unit and functional tests? I'd rather ONLY incorporate it into the needed files, just the unit tests.
I'm new to testing practices in general. Is it common in Rails to test validations (for example, test: validates_presence_of :name)? Most of my functions that test validations on a model are all basically the same (just swap in and out correct fixture and attribute name). Doesn't seem very DRY. Looking for a way to refactor.
Thanks.
You can place the code in the test/test_helper.rb file.
You should already find a code fragment that looks like this
class ActiveSupport::TestCase
self.use_transactional_fixtures = true
self.use_instantiated_fixtures = false
end
If the code should be used in all your tests, you can add your methods in the ActiveSupport::TestCase class. Otherwise, wrap them into a Module and mix the module where required.
It's a good practice to test validations not to test the validation itself (the validates_presence_of macro is already tested in the Rails codebase), but to make sure chances in your code don't affect your class business.
For instance, there might be validation which needs to be triggered only in specific events. Or you might want to make sure no one removed your super-secret validation on that specific model.
If you want to test your model validations, I encourage you to check out shoulda. Shoulda provides several handy methods to test your validations.
class PostTest < ActiveSupport::TestCase
should belong_to(:user)
should validates_presence_of(:id)
end
In one of my projects I need to collaborate with several backend systems. Some of them somewhat lacks in documentation, and partly therefore I have some test code that interact with some test servers just to see everything works as expected. However, accessing these servers is quite slow, and therefore I do not want to run these tests every time I run my test suite.
My question is how to deal with a situation where you want to skip certain tests. Currently I use an environment variable 'BACKEND_TEST' and a conditional statement which checks if the variable is set for each test I would like to skip. But sometimes I would like to skip all tests in a test file without having to add an extra row to the beginning of each test.
The tests which have to interact with the test servers are not many, as I use flexmock in other situations. However, you can't mock yourself away from reality.
As you can see from this question's title, I'm using Test::Unit. Additionally, if it makes any difference, the project is a Rails project.
The features referred to in the previous answer include the omit() method and omit_if()
def test_omission
omit('Reason')
# Not reached here
end
And
def test_omission
omit_if("".empty?)
# Not reached here
end
From: http://test-unit.rubyforge.org/test-unit/en/Test/Unit/TestCaseOmissionSupport.html#omit-instance_method
New Features Of Test Unit 2.x suggests that test-unit 2.x (the gem version, not the ruby 1.8 standard library) allows you to omit tests.
I was confused by the following, which still raises an error to the console:
def test_omission
omit('Reason')
# Not reached here
end
You can avoid that by wrapping the code to skip in a block passed to omit:
def test_omission
omit 'Reason' do
# Not reached here
end
end
That actually skips the test as expected, and outputs "Omission: Test Reason" to the console. It's unfortunate that you have to indent existing code to make this work, and I'd be happy to learn of a better way to do it, but this works.
We have a ton of non-user data: 500 product types that haven't changed in 20 years, 200GB of geospatial data that never changes (Queens is always 40.73N/73.82W)... etc. It's the same in Development and Production. It should be the same in Test, but the during testing Rails empties all of the test tables, and it takes a ton of time to re-populate during testing.
What is the Rails way to partition this non-user data so that it doesn't have to be repopulated in Test?
The documentation for this is found in the Fixtures class. (Search for "Transactional fixtures" on that page.)
The example they give starts out like this:
class FooTest < ActiveSupport::TestCase
self.use_transactional_fixtures = true
self.use_instantiated_fixtures = false
...
One of the projects I work on uses a test database with zero fixtures, so we just define this globally in test_helper.rb.
class ActiveSupport::TestCase
self.use_transactional_fixtures = true
self.use_instantiated_fixtures = false
end
jdl shows you the settings to use for enabling and disabling transactional_fixtures, you should be able to set:
# Use self in ActiveSupport::TestCase if you don't have a config block
# in test/test_helper.rb
#
config.use_transactional_fixtures = false
And stop Rails from trying to load fixtures before each run of your tests. The downside is you can't assume all your fixtures are loaded into the DB.
Real Answer
You have too much data in your fixtures. The Railsy thing to do it load only the necessary data in test fixtures; You do not need 200G of geospatial data (what freaking dataset is that anyway? that sounds way too big), and you probably don't need all 500 products.
Tests are for your code, so only include the few geospatial points you need for a test, or only include a few products with unique properties. Keep the DB light enough to be loaded quickly.
Your test fixtures should be separate from you application bootstrapping data, take advantage of that.
Real Real Answer
Don't touch the database in your tests (or, touch it very little). The database is slow and fixtures are difficult or impossible to maintain well. Instead, try using a stubbing framework like Mocha or flexmock. It's faster, and makes your tests read in a clearer manner. Tests are for code, you can stub the database out of the situation and trust that ActiveRecord works (because...it's tested too! :-).
If you do choose to stick with fixtures, I recommend using factory_girl instead of the built in Rails fixtures. You'll have a much better starting point.
This seems like a simple question but I can't find the answer anywhere. I've noticed that in general, tests in a Ruby on Rails app can be written as:
test "the truth" do
assert true
end
or
def the_truth
assert true
end
It seems newer material writes tests the first way, but I can't seem to find a reason for this. Is one favored over the other? Is one more correct? Thanks.
There has been a shift in recent years from short, abbreviated test names to longer, sentence-like test names. This is partly due to the popularity of RSpec and the concept that tests are specs and should be descriptive.
If you prefer descriptive test names, I highly recommend going with the test method. I find it to be more readable.
test "should not be able to login with invalid password" do
#...
end
def_should_not_be_able_to_login_with_invalid_password
#...
end
Also, because the description is a string it can contain any characters. With def you are limited in which characters you can use.
I believe the first method was implemented starting with Rails 2.2.
As far as I am aware, it simply improves readability of your code (as def can be any function while test is used only in test cases).
Good luck!
As Mike Trpcic suggests you should check out RSpec and Cucumber. I'd like to add that you should also take a look at:
Shoulda (http://github.com/thoughtbot/shoulda/tree/master)
Factory Girl (http://github.com/thoughtbot/factory_girl/tree/master)
Shoulda is a macro framework for writing concise unit tests for your models/controllers, while the second is a replacement for fixtures.
I would suggest doing your testing with either RSpec or Cucumber. I use both to test all my applications. RSpec is used to test the models and controllers, and Cucumber tests the Views (via the included Webrat functionality).