Kernel#caller provides the desired behaviour. Also, it is good practice to use Kernel#warn for warnings (which sends output to $stderr by default), instead of puts-ing out to $stdout where it is inseparable from the output of your specs:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # figure out where we are being loaded from if $LOADED_FEATURES.grep(/spec\/spec_helper\.rb$/).any? warn <<-MSG =================================================== It looks like spec_helper.rb has been loaded multiple times. Normalize the require to: require "spec/spec_helper" Things like File.join and File.expand_path will cause it to be loaded multiple times. Loaded this time from: #{caller.join("\n ")} =================================================== MSG end end |
cheers
]]>1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # figure out where we are being loaded from # see: http://kpumuk.info/ruby-on-rails/my-top-7-rspec-best-practices/ def prevent_multiple_require(regex, standardized_require_path) if $LOADED_FEATURES.grep(regex).any? begin raise "foo" rescue => e puts <<-MSG =================================================== It looks like #{File.basename(standardized_require_path)}.rb has been loaded multiple times. Normalize the require to: require "#{standardized_require_path}" Things like File.join and File.expand_path will cause it to be loaded multiple times. Loaded this time from: #{e.backtrace.join("\n ")} =================================================== MSG end end end |
And then used in my spec helper like this:
1 2 | require 'prevent_multiple_require' prevent_multiple_require(/spec_helper\.rb/, "spec_helper") |
This improves on #7 because you can customize the regex used for matching, and reuse it for other situations. I have made it as simple as possible because other paths that may require spec_helper may use ‘..’.
]]>Flyboy Art,
Indeed, it is faster to write the code in the first place. In some languages, such as Lisp (or Scheme), incredibly so, using the REPL. And, in the case of functional languages (NOT ruby), you can even prove that the code is correct.
The problem with that is when things change. And they *will*. You can’t do simple refactorings like changing a method name, while knowing for sure that your change didn’t break an obscure section in your app. Or, when you figure out a more efficient way to do something, it your business logic is still functioning.
]]>1 | require File.join(File.directory(__FILE__), '..', '..', 'spec_helper') |
only load the file once per directory level, since the only difference is the number of ‘..’s. Second, if I want to be in the spec directory when I run, I should be allowed:
1 | require File.expand_path(File.join(File.directory(__FILE__), '..', '..', 'spec_helper')) |
Second, the problem of missing problems is only a problem if you don’t use integration tests and stories.
You have classes A and B. Each should be tested in near-isolation. You especially want to isolate from the database, for various reasons. BUT… you also need to have an integration test that runs A->B->database. If the later breaks, fixing it will break the obsolete unit tests, which is as it should be.
The other thing you did not seem to mention is the importance of testing interfaces, not implementations. Maybe that is a no-brainer to you, but code changes much faster than the interface.
]]>Hey Myron, thank you for the reply. I have updated an article with more consistent context usage, it was my failure.
About mocking in controllers, yes it makes sense. Sometimes. When you pretty sure you models work as expected, when you confident in their work. As I said, in some circumstances you can get false positives, for example, when add after_create hook which fails with an exception, or new super-useful NOT NULL restriction on one of columns in the database. If you have all your models covered with — it’s ok, use mocks to get controller specs clean in simple. By the way, did you hear about stub_model?
About mocks: In general, I agree with you that over mocking is a problem. But I disagree that it’s always better to use no mocking or stubbing in your controller specs. In my opinion, the danger of mocking is directly proportional to how likely it is the interface you are mocking will change. So, mocking a class method that frequently changes its interface is dangerous and should be avoided. Mocking an interface that is highly unlikely to change is generally safe and can lead to less brittle tests.
So, for example, when I’m spec’ing the #update and #create actions of a controller, I mock #valid? so that it returns true or false based on which code path I want to test. The alternative is to pass valid or invalid attributes in the request, but this leads to fragile specs: now my controller specs have to know what attribute values are valid and invalid, and when my model validation logic changes, my controller specs begin to fail. Really, I don’t care in my controller specs what is valid and invalid…I just care that when the attributes are valid, it does one thing, and when they are invalid, it does another thing. #valid? has been around in ActiveRecord for as long as I can remember (I imagine it was there from the first release) and the likely hood of that interface ever changing is approximately nil. I think it’s safe and useful to use mocking here.
About describe vs. context: In your example, you use context for both “.top” and “when just created”. I think context is appropriate for the latter (since “when just created” describes a context the examples run in) but describe is more appropriate for the former. “.top” isn’t a context; rather it’s simply grouping all the examples where you are describing the top method. I use use describe in these cases since you’re describing the behavior of a method.
]]>Okay. Please, share your experience with us. What makes you sure that your code working and working right? How easy will it be for you to change some logic in your project or just do a refactoring and be sure that you didn’t broke something your project?
]]>