1

I'm upgrading a Rails 4.0 app to Rails 4.2. All the tests passed prior to the upgrade. However, I am now getting several errors (but no failures). This is the output of one of the tests:

Run options: --seed 30437

# Running:

E

Finished in 1.738307s, 0.5753 runs/s, 0.0000 assertions/s.
/opt/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/testing/assertions/routing.rb:171:in `method_missing': private method `location' called for #<[MyTestClass]:0xb46557c> (NoMethodError)
    from /opt/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/actionpack-4.2.1/lib/action_dispatch/testing/integration.rb:397:in `method_missing'
    from /opt/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/minitest-5.6.0/lib/minitest/test.rb:265:in `block in to_s'
    from /opt/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/minitest-5.6.0/lib/minitest/test.rb:264:in `map'
    from /opt/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/minitest-5.6.0/lib/minitest/test.rb:264:in `to_s'
    from /opt/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/minitest-5.6.0/lib/minitest.rb:580:in `%'
    from /opt/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/minitest-5.6.0/lib/minitest.rb:580:in `block in aggregated_results'
    from /opt/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/minitest-5.6.0/lib/minitest.rb:579:in `each'
    from /opt/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/minitest-5.6.0/lib/minitest.rb:579:in `each_with_index'
    from /opt/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/minitest-5.6.0/lib/minitest.rb:579:in `each'
    from /opt/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/minitest-5.6.0/lib/minitest.rb:579:in `map'
    from /opt/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/minitest-5.6.0/lib/minitest.rb:579:in `aggregated_results'
    from /opt/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/minitest-5.6.0/lib/minitest.rb:566:in `report'
    from /opt/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/minitest-5.6.0/lib/minitest.rb:638:in `each'
    from /opt/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/minitest-5.6.0/lib/minitest.rb:638:in `report'
    from /opt/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/minitest-5.6.0/lib/minitest.rb:134:in `run'
    from /opt/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/minitest-5.6.0/lib/minitest.rb:56:in `block in autorun'

I can't seem to find anything in my code that could be causing this error. Looking at some of the files mentioned in the stacktrace, it looks like it is erroring while trying to generate a failure message. (Double fail...)

What is the cause of this error?

Edit:

The first line of my test is s = login(:user). If I place a return before that line, the test passes, but if I place it after that line, I still get the error. The login function is defined in my test_helper.rb as follows:

def login(user)
  open_session do |sess|
    u = users(user)
    sess.extend(MySession)
    sess.get "/users/sign_in"
    sess.assert_response :success
    sess.post_via_redirect "/users/sign_in",
      user: {
        email: u.email,
        password: "<password>"
      }
    assert_equal '/', sess.path
    assert_equal "Signed in successfully.", sess.flash[:notice]
  end
end

The module MySession contains a few helper methods.

Edit 2:

I opened a rails console session, required my test class, and did MyTestClass.private_methods. This was the output:

=> [:initialize, :_stash_object_in_method, :_superclass_delegating_accessor, :included, :extended, :prepended, :method_added, :method_removed, :method_undefined, :initialize_copy, :attr, :attr_reader, :attr_writer, :attr_accessor, :initialize_clone, :remove_const, :using, :remove_method, :undef_method, :alias_method, :public, :protected, :private, :define_method, :attr_internal_ivar_name, :attr_internal_define, :DelegateClass, :Digest, :timeout, :default_src_encoding, :Nokogiri, :irb_binding, :create_fixtures, :load, :require, :initialize_dup, :sprintf, :format, :Integer, :Float, :String, :Array, :Hash, :warn, :raise, :fail, :global_variables, :__method__, :__callee__, :__dir__, :eval, :local_variables, :iterator?, :block_given?, :catch, :throw, :loop, :respond_to_missing?, :trace_var, :untrace_var, :at_exit, :syscall, :open, :printf, :print, :putc, :puts, :gets, :readline, :select, :readlines, :p, :srand, :rand, :trap, :require_relative, :proc, :lambda, :binding, :caller, :caller_locations, :exec, :fork, :exit!, :system, :spawn, :sleep, :exit, :abort, :Rational, :Complex, :set_trace_func, :gem_original_require, :Pathname, :URI, :rubygems_require, :BigDecimal, :j, :jj, :JSON, :not_implemented, :y, :open_uri_original_open, :pp, :singleton_method_added, :singleton_method_removed, :singleton_method_undefined, :method_missing]

Edit 3:

I opened a rails console session, required my test class, and did test = MyTestClass.new and then test.private_methods. This time, the output did contain :location. This app does have a Location model, and this output appeared in between several other of the app's models, so I suspect that is the problem. The question is now: why do my test classes have private methods named after my app's models? How can I fix or work around this problem? (Obviously I could rename the Location model, but I'd prefer to avoid that, if possible.)

Scott Weldon
  • 9,673
  • 6
  • 48
  • 67

2 Answers2

1

Did the location method change from public to private on whatever class you're calling it on between Rails 4.0 and 4.2?

Maybe I'm misunderstanding, but the error seems pretty straightforward. Somewhere (in your code, or maybe a gem you rely on that's changed versions as well) a method called location is being called which is private. The stack track shows you where it's happening, so take a look at that code and see what's going on.

Might also be helpful to see the test code, but the stack trace is pointing you to the source from which you can trace back what's going on.

I looked through the code on github as well and can't find anything. Any chance you defined a method called location on MyTestClass that overrides the one in MiniTest::Test ? Also, if you go into your console and simply require the MyTestClass, and call .private_methods on it (or rather an instance of it), does :location indeed show up in the list? Any include statements anywhere that you can find in your code that might be bringing in a location method into MyTestClass?

It looks like this question/answer might provide a way to track down where these methods are coming from.

Community
  • 1
  • 1
jefflunt
  • 33,527
  • 7
  • 88
  • 126
  • That's the thing: I'm not calling a `location` method anywhere. I found some references to it in the `minitest` gem (mentioned in the stack trace), but the file that contains it (`.../minitest-5.6.0/lib/minitest/test.rb`) does not contain the word `private` anywhere. – Scott Weldon Apr 28 '15 at 16:05
  • No to all three questions. See edit. The only `include` statement in my test class is `test_helper`. – Scott Weldon Apr 28 '15 at 17:29
  • Oops, actually I called `.private_methods` on the class, not the instance of it. I'll try that instead. – Scott Weldon Apr 28 '15 at 17:29
  • I've edited my post again. I think I've found the cause of the problem, now I just need to determine why. – Scott Weldon Apr 28 '15 at 17:37
  • If you edit the contents of your comment into your answer, I will likely accept it (especially if you know why this happens, and/or how I can work around it). – Scott Weldon Apr 29 '15 at 17:01
  • Thanks. Looks like the link is missing though? – Scott Weldon Apr 30 '15 at 01:58
  • Thanks, got it figured out. I've suggested an edit with my results. – Scott Weldon Apr 30 '15 at 15:49
  • Your edit was rejected by the community. They feel it should be added as an answer (you can accept your own answer). Just thought I'd pass that feedback to you. – jefflunt Apr 30 '15 at 18:39
  • Done. I'll leave your answer as accepted, since you helped me find the source of the problem. Thanks! – Scott Weldon Apr 30 '15 at 19:06
0

Using the .method and .source_location methods from @jefflunt's link, I was able to find the cause of the problem. When I did test.method(:location).source_location from the rails console, I got this output:

=> ["/opt/rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/activerecord-4.2.1/lib/active_record/fixtures.rb", 885]

When I looked up that line in that file, I found a method that defines private accessor methods for each fixture. Since I had fixtures defined for my Location model, that was the cause of this problem.

Since I don't see another way around this problem (aside from perhaps ditching fixtures, which I'm not ready to put time into just yet), I'll be renaming my Location model.

Scott Weldon
  • 9,673
  • 6
  • 48
  • 67