Calling a Sinatra app instance method from TestCase

后端 未结 2 1114
礼貌的吻别
礼貌的吻别 2021-01-04 06:14

I have an util method into a Sinatra application and I would like to tested from my TestCase.

The problem is that I don\'t know how to invoke i

相关标签:
2条回答
  • 2021-01-04 06:45

    The problem you are encountering is, that MyApp.new does not return an instance of MyApp but an instance of the middleware wrapping your App (usually Rack::Head or Sinatra::ShowExceptions). A good explanation can be found in the thread Sinatra Usage Question / Rack App.

    The only solution I can think of is to change your instance method to a class method which can be called without the instance itself. As the instance of your App may be freshly instantiated for every request, an instance method probably doesn't have much advantages over a class method in your scenario.

    Edit:

    In the upcoming Sinatra 1.4 the initialization will change. Sinatra::Base.new will return a Sinatra::Wrapper instance, which exposes #settings and #helpers. This may help solve the problem of accessing Sinatra::Base instance methods. See the Sinatra Changelog for more information.

    0 讨论(0)
  • 2021-01-04 07:00

    Sinatra aliases the new method to new! before redefining it, so the simplest solution is to use that instead:

    def app
      MyApp.new!
    end
    

    Of course I only noticed that after I’d come up with the following, which I’ll leave in as it could be useful/informative.


    A possible way to get round Sinatra redefining the new method and returning a complete Rack app a get hold of an instance your actual base class is to do what the “real” new method does yourself:

    def app
      a = MyApp.allocate
      a.send :initialize
      a
    end
    

    This is a bit of a hack, but it might be useful for testing.

    Another technique would be to “walk” the middleware stack until you got to your class. The following is a little fragile, as it depends on all the middleware involved to use the name @app to refer to the next app in the stack, but this is fairly common.

    def app
      a = MyApp.new
      while a.class != MyApp
        a = a.instance_variable_get(:@app)
      end
      a
    end
    

    That won’t work on the yet to be released Sinatra 1.4 though (at least not on the current master, which is commit 41840746e866e8e8e9a0eaafc53d8b9fe6615b12), as new now returns a Wrapper class and the loop never ends. In this case you can grab the base class directly from the @instance variable:

    def app
      MyApp.new.instance_variable_get :@instance
    end
    

    (note this last technique may well change before the final 1.4 release).

    0 讨论(0)
提交回复
热议问题