Comments on: My top 7 RSpec best practices https://kpumuk.info/ruby-on-rails/my-top-7-rspec-best-practices/ In my blog I'll try to describe about interesting technologies, my discovery in IT and some useful things about programming. Tue, 23 Sep 2014 21:49:21 +0000 hourly 1 https://wordpress.org/?v=6.6.1 By: Ryan Biesemeyer https://kpumuk.info/ruby-on-rails/my-top-7-rspec-best-practices/comment-page-1/#comment-494931 Tue, 23 Sep 2014 21:49:21 +0000 http://kpumuk.info/?p=1080#comment-494931 There is no need to raise an exception in order to get a backtrace; 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
]]>
By: Fabio Pereira https://kpumuk.info/ruby-on-rails/my-top-7-rspec-best-practices/comment-page-1/#comment-359281 Thu, 04 Apr 2013 17:47:58 +0000 http://kpumuk.info/?p=1080#comment-359281 Hi, I really liked your 4th suggestion on mocks. Very good way to explain the “over mocking” problem. I’ll refer to your post when people ask me more about it. We called it “Tautological TDD – TTDD”, this posts talks about it:
http://fabiopereira.me/blog/2010/05/27/ttdd-tautological-test-driven-development-anti-pattern/

cheers

]]>
By: Peter Boling https://kpumuk.info/ruby-on-rails/my-top-7-rspec-best-practices/comment-page-1/#comment-331013 Mon, 06 Aug 2012 18:05:20 +0000 http://kpumuk.info/?p=1080#comment-331013 I methodized #7 into a file ‘prevent_multiple_require.rb’:

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 ‘..’.

]]>
By: dB. https://kpumuk.info/ruby-on-rails/my-top-7-rspec-best-practices/comment-page-1/#comment-293871 Tue, 16 Aug 2011 12:37:51 +0000 http://kpumuk.info/?p=1080#comment-293871 This could use an update for RSpec2. Here’s a part, breaking up tests into suites: http://code.dblock.org/rspec-fuubar-breaking-tests-into-suites.

]]>
By: Stephen Eilert https://kpumuk.info/ruby-on-rails/my-top-7-rspec-best-practices/comment-page-1/#comment-291475 Mon, 21 Mar 2011 17:44:13 +0000 http://kpumuk.info/?p=1080#comment-291475 In reply to FlyboyArt.

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.

]]>
By: Walter Yu https://kpumuk.info/ruby-on-rails/my-top-7-rspec-best-practices/comment-page-1/#comment-291366 Thu, 10 Mar 2011 21:40:04 +0000 http://kpumuk.info/?p=1080#comment-291366 Excellent write-up, thanks for sharing! The last point with the snippet is useful, I placed it into my spec_helper.rb file.

]]>
By: AnOldHacker https://kpumuk.info/ruby-on-rails/my-top-7-rspec-best-practices/comment-page-1/#comment-289564 Thu, 04 Nov 2010 18:59:55 +0000 http://kpumuk.info/?p=1080#comment-289564 First, lines like

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.

]]>
By: Dmytro Shteflyuk https://kpumuk.info/ruby-on-rails/my-top-7-rspec-best-practices/comment-page-1/#comment-285492 Wed, 16 Dec 2009 22:23:39 +0000 http://kpumuk.info/?p=1080#comment-285492 In reply to Myron.

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?

]]>
By: Myron https://kpumuk.info/ruby-on-rails/my-top-7-rspec-best-practices/comment-page-1/#comment-285487 Wed, 16 Dec 2009 17:44:42 +0000 http://kpumuk.info/?p=1080#comment-285487 These are some good tips, but I don’t fully agree with all them. Particular points 4 and 5:

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.

]]>
By: erka https://kpumuk.info/ruby-on-rails/my-top-7-rspec-best-practices/comment-page-1/#comment-285452 Mon, 14 Dec 2009 12:11:19 +0000 http://kpumuk.info/?p=1080#comment-285452 Hey FlyboyArt,

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?

]]>