I'm still new top rspec, so please excuse if this is an easy one but I wasn't able to find an answer on Google. I have a library module that handles parsing some data from an API response. I have written tests, and all that works fine, however I'd like to move the fake API response data into an external file since it's pretty long and makes the test harder to read. I looked at fixtures and factories, but those are really for models, and this is just a really long xml snippet. My current test looks something like this
describe :my_test do
let(:my_var) { REALLY_LONG_XML_SNIPPET}
....test code...
end
How can I move REALLY_LONG_XML_SNIPPET into an external file?
This is what I use in my specs:
let(:doc) { IO.read(Rails.root.join("spec", "fixtures", "api_response.xml")) }
It will copy the file's contents into a string.
Note that I have turned off the default ActiveRecord fixtures for RSpec, so I put my fixtures in that directory instead.
Update: with Rspec Rails 3.5 and newer
one can also use file_fixture
let(:doc) { file_fixture("api_response.xml").read }
for
files stored in spec/fixtures/files by default
but file location can be customized.
Related
I'm writing RSpec tests and I have come to a point where I am not reading the same opinions on different websites. The directory structure for RSpec is clear when we are dealing with spec/controllers and spec/models directories, but the conflicting information I am getting deals with testing views.
I would like to just put these tests in a spec/integration/ directory, but I have read that it's supposed to be under spec/integration, but another book says spec/requests. Does this matter?
To further complicate the situation, I have read conflicting information on naming the actual file names of the tests! For example, if I had a controller/model/view directory called 'people' (I i use haml), I should name the files like this:
spec/integration/people.html.haml_spec.rb
However, another book suggests this:
spec/requests/people_spec.rb
I would like a little explanation of naming conventions within RSpec and WHY I should name the view tests specific names, as well as whether or not it matters to put them under spec/integration or spec/requests. I feel like I'm going with the wind here.
Any help is greatly appreciated.
Check the dates of the books and the versions of RSpec for which they were written. The naming structure has changed slightly over time.
According to the docs for rspec-rails, request specs can go in spec/requests, spec/api, or spec/integration. I prefer to put request specs in spec/requests.
To make things more interesting, if you are using Capybara with rspec-rails, it will work with spec/requests for Capybara 1.x, and spec/features for Capybara 2.
As to individual spec file names, when there is a specific class under test, like a Rails model, you should use an analogous spec file name:
app/models/user.rb -> spec/models/user_spec.rb
View specs should use the template name:
app/views/users/index.html.erb -> spec/views/users/index.html.erb_spec.rb
Namespaced models should include the namespace in the spec file path:
app/models/admin/user.rb -> spec/models/admin/user_spec.rb
The RSpec scaffold generator is a good guide for showing where these specs belong.
When there is no specific class under test, as is the case with request specs, IMHO you should feel free to use a name that describes the thing being tested. E.g. spec/requests/place_an_order_spec.rb.
The files read by the rspec gem are simply those that end in _spec.rb and that are anywhere in the hierarchy below the spec folder as long as the top of the hierarchy is an alpha-numeric word (that is, files under a folder named spec/##/ would not be considered in generating specs.) This is the relevant line of code that implements this, in /gems/rspec-rails-2.14.1/lib/rspec/rails/tasks/rspec.rake:
namespace :spec do
types = begin
dirs = Dir['./spec/**/*_spec.rb'].
map { |f| g=f.sub(/^\.\/(spec\/\w+)\/.*/, '\\1') ; puts ">>> Found #{g}."; g }.
uniq.
select { |f| File.directory?(f) }
Hash[dirs.map { |d| [d.split('/').last, d] }]
end
So all the text in the filename previous to _spec.rb is a convention - it doesn't change how Rails processes the files.
I'd have to read through the code a lot more to figure out what the significance of each folder name, under spec, is - it gets passed through to the Rake spec task that's created, so it's being used for something but I don't know what.
I have a more conceptual question in Rails... or Ruby for that matter:
Is it best to call a require right before the method that needs it, group my requires at the beginning of the class or somewhere in an initializer when Rails boots?
Does it matter from a performance point of view? From a readability point of view? Does it make a difference if I'm using Rails 3?
Thanks!
If you're concerned about performance then you should require things in the context of where they are needed so that if that portion of your code is not exercised, the library is not loaded. Any subsequent calls to require have no effect as that file has already been loaded. This ends up looking like something along the lines of:
if (user.using_openid?)
require 'openid'
# ... Do OpenID stuff
end
While this is more efficient in terms of resources, it can make it very difficult to determine the dependencies of your application. Declaring these up-front makes it clear to other people maintaining the software. Keep in mind that "other people" always includes your future self when you've forgotten about some details of your application.
You're technically allowed to require anything at any time, late or early, but declaring your requirements up front is better from a design perspective. If you find that there is an element that is used only intermittently and takes an unusual amount of time or memory to load, then you should probably document that up front in your requirements file. For example:
require 'library1'
require 'library2'
require 'library3'
require 'library4'
require 'library5'
# Other libraries loaded as required:
# * slowimagelibrary
# * slowencryptionlibrary
# * openid
Arguably this is less of an issue with bundler because you can have your gems declared up front more formally and the actual require call can come later.
If you consider vanilla Ruby, 'require' is mostly used in the first lines, because you then are sure you have access to what you need, and it is easier to find and read what dependency you need.
There are a few cases when you want to load a gem only in a method, because this is not really needed for your script to work (e.g.: a optional visualization).
With Rails, I believe it depends on what you want to do.
If you use Bundler, you can assume your gem has been 'required' (you can of course override what is required with the :require option).
If it is some stuff you want to autoload when the server start (like validators or form builders), then you should look how to do with the config (autoload_paths and eager_load_paths).
require can also be used to load only a part of a gem, like an extension to it. Then it is of course required where the configuration is.
You might be concerned if you work in a multi-threaded environment, as they are some problems with that. You must then ensure everything is loaded before having your threads running. (Something like the class constant is loaded, but the methods not yet, there was a good article but I can not find it anymore).
You might also want to try {Module,Kernel}.autoload, Rails extensively use it to load only what is necessary when accessed (but it looks rather ugly).
You can also hack it yourself with const_missing (so this can do plain lazy-loading, if you accept a structure).
This is a simple example (will not be appropriate for nested classes).
def Object.const_missing c
if (file = Dir["#{c.downcase}.rb"]).size == 1
require_relative(file)
end
if const_defined? c
const_get c
else
super # Object < Module
end
end
About performance, a call to require is relatively expensive, so if you know you are going to use it, do it only once if possible. However, to manage complex dependencies within your project, you might need to require relative files. Then require_relative is the way to go in 1.9.
Lastly, for a project, I would recommend to require all in the main file in lib/, with some Dir["**/*.rb"] expression. You would then rarely need to require_relative, because it is only needed if you reference in the body of the class another constant (all the contents of the methods are not resolved, so there is no problem with that).
Another solution would be to define these constants in your main file, it would also give you an idea of the structure.
I have the following class that I'd like access to within certain controllers in my app:
class Spreedly
include HTTParty
base_uri 'https://example.com/api/1234'
basic_auth 'user', 'xyz124'
headers 'Accept' => 'text/xml'
headers 'Content-Type' => 'text/xml'
format :xml
end
Where would I put that class so that I could then access it in a controller like Spreedly.post(xyz)?
You can simply place this in a file called spreedly.rb in the lib/ directory. It'll be auto-loaded by rails and will be available for use.
True, but there is nothing stopping you from putting it in your app/models directory.
And to me it seems a better place to put it - because your are accessing data like any other model in your app, and when you reference Spreedly.post etc from your controllers another programmer will naturally (imho) look in the app/models directory first before the /lib ..
Anything that needs to be referenced in multiple places or anything that is large, I put in lib. If it is tiny, and if it is used in a single model, I will put it in the same model file.
I'm very interested in testing this custom classes quickly, just as if you we're testing any other model. One problem I faced by trying to put the file under /lib, is that Spork or Zeus will reboot the environment to run the test.
I love the idea of storing the file under /lib, but this is making my continuos testing process slower. I ended up putting it under app/models.
If there was a way to test a a file under /lib more easily, that'd be great.
I am facing an issue where my Rails application is set to cache classes when run in the staging or production environment. While load_paths only contains 'app/models', it appears that the initialization steps recursively caches everything in 'app/models'.
# Eager load application classes
def load_application_classes
if configuration.cache_classes
configuration.eager_load_paths.each do |load_path|
matcher = /\A#{Regexp.escape(load_path)}(.*)\.rb\Z/
Dir.glob("#{load_path}/**/*.rb").sort.each do |file|
require_dependency file.sub(matcher, '\1')
end
end
end
end
The problem in this is that we have a sub directory within 'app/models' that contains files with require statements that reference a concurrent JRuby environment. Since Rails knows nothing of this environment our application breaks on load.
As it stands, here are the proposed solutions...unfortunately only #1 is ideal.
1) The simplest solution would be to exclude the culprit sub directory, but have not found anything how to accomplish this.
2) Monkey patch the load_application_classes method to skip the specific sub directory.
3) Move the sub directory out from under 'app/models'. Feels a bit hackish and would require quite a few code changes.
Thoughts?
As a temporary measure you could go with a version of option 2 and override the definition of load_application_classes, replacing it with an empty implementation. That would force you to explicitly require the classes you need but it would give you complete control over what gets loaded and would be a completely transparent solution.
It sounds like your application is sufficiently sophisticated that it's growing beyond the Rails framework. I know that this doesn't directly answer your question so appologies in advance but you may want to consider looking at an alternative Ruby framework like Merb. Rails is great but sooner or later you bump into edge of the framework - sounds like that's where you are now.
We made the switch to Merb last year and haven't regreated it.
Chris
I have never worked with web services and rails, and obviously this is something I need to learn.
I have chosen to use hpricot because it looks great.
Anyway, _why's been nice enough to provide the following example on the hpricot website:
#!ruby
require 'hpricot'
require 'open-uri'
# load the RedHanded home page
doc = Hpricot(open("http://redhanded.hobix.com/index.html"))
# change the CSS class on links
(doc/"span.entryPermalink").set("class", "newLinks")
# remove the sidebar
(doc/"#sidebar").remove
# print the altered HTML
puts doc
Which looks simple, elegant, and easy peasey.
Works great in Ruby, but my question is: How do I break this up in rails?
I experimented with adding this all to a single controller, but couldn't think of the best way to call it in a view.
So if you were parsing an XML file from a web API and printing it in nice clean HTML with Hpricot, how would you break up the activity over the models, views, and controllers, and what would you put where?
Model, model, model, model, model. Skinny controllers, simple views.
The RedHandedHomePage model does the parsing on initialization, then call 'def render' in the controller, set output to an instance variable, and print that in a view.
I'd probably go for a REST approach and have resources that represent the different entities within the XML file being consumed. Do you have a specific example of the XML that you can give?