Testowanie

Kiedy testuje jedna z moich metod:

should 'post method' do post :method, :param1 => @param1, :param2 => @param2 assert_response :success end
Nie chce aby wywolywala on podczas testu produkcyjnych zachowan. Mam w tej metodzie wywolywana prywatna metode i podczas tego testu zwracana jest prawdziwa wartosc tej metody. Czy da sie jakos zbudowac atrape dla tej metody aby nie zwracala prawdziwych wartosci. Oraz jak moge przetestowac taki routing ktory zawiera constraints?

[quote=wlodi]Kiedy testuje jedna z moich metod:
Nie chce aby wywolywala on podczas testu produkcyjnych zachowan. Mam w tej metodzie wywolywana prywatna metode i podczas tego testu zwracana jest prawdziwa wartosc tej metody. Czy da sie jakos zbudowac atrape dla tej metody aby nie zwracala prawdziwych wartosci. Oraz jak moge przetestowac taki routing ktory zawiera constraints?[/quote]
Jeśli dobrze rozumiem chodzi ci o: http://rspec.info/documentation/mocks/stubs.html

A.should_receive(:metoda).with(:argumenty).and_return(:wartosci_zwracane)

Masz na myśli testy jednostkowe czy integracyjne ?

Witam, chodzi mi o testy funkcjonalne kontrolera. Kiedy testuje metode zwraca mi ona prawdziwe zapytania. W tym momencie requesty do serwera. Jak moge odzwierciedlic takie requesty aby byly najbardziej wiarygodne podczas testow? Stubs bjest ok ale nie mozna chyba uzywac dla testowania metod ktora sama wykorzystuje metode prywatna. Wlasnie ta prywatna metode chce jakos przetworzyc aby nie zwracala mi prawdziwych wartosci podczas testowania.

A co robi ta prywatna metoda jeśli można wiedzieć ? Jeśli to nazbyt prywatne pytanie to przepraszam :slight_smile:

Metoda make_request tworzy callbacki do serwerow za pomoca gemu Typhoeus jak ponizej w kodzie. Chcialbym to jakos sprowadzic do makiety aby nie wywolywac prawdziwych callbackow do serwera podczas testow.

Gdy testuje metode w tescie funkcjonalnym serialowy_swiat prywatna metoda wywoluje prawdziwe callbacki.

[code]setup do
@param1 = “notofferid”
end

should ‘post serialowy_swiat’ do
post :serialowy_swiat, :param1 => @param1, :param2 => @param2
assert_response :success
end[/code]

[code] def serialowy_swiat

if params[:offer_id].to_i >= 0 && params[:offer_id].present?

  make_request(
    "http://www.serialowyswiat.pl/",
    {
      :offer_id     => params[:offer_id],
    }
  )
else
  render :text => "Bad Request", :status => 401
end

end

def make_request(url, request_params, landing_page = false)

hydra   = Typhoeus::Hydra.new
request = Typhoeus::Request.new(url,
                                :timeout       => 100000,
                                :cache_timeout => 60,
                                :verbose       => true,
                                :params        => request_params )

request.on_complete do |response|

  if response.success?

    log_action("Server response: #{response.body}")
    landing_page.blank? ? (render :nothing => true) : (redirect_to landing_page)

  elsif response.timed_out?

    log_action("Server Response URL got a time out")
    render :text => 'Server got a time out', :status => 401

  elsif response.code == 0

    # Could not get an http response, something's wrong
    log_action("#{response.curl_error_message}", :warn)
    render :text => response.curl_error_message, :status => 401

  else

    # Received a non-successful htpp response.
    log_action("HTTP request failed: #{response.code.to_s}", :warn)
    render :text => response.code.to_s, :status => 401

  end

end

hydra.queue(request)
hydra.run

end[/code]

Hej probuje utowrzyc makiete dla metodz make_request:

SerialowyController.any_instance.stubs(:make_request).returns(:render)

ale niestety caly czas podczas testow pojawia mi sie komunikat:

test:post serialowy_swiat. (SerialowyControllerTest): ActionView::MissingTemplate: Missing template serialowy/serialowy_swiat with {:handlers=>[:erb, :rjs, :builder, :rhtml, :rxml], :formats=>[:html], :locale=>[:en, :en]} in view paths "/home/wlodi/serialowy/app/views" test/functional/serialowy_controller_test.rb:14:in `block (2 levels) in <class:SerialowyControllerTest>'
Nie wiem jak napisac makiete dla tej metody ktora zwraca :render :nothing => true

Ma ktos jakis pomysl jak to zrobic?

Jak używasz Typhoeus to nie stubuj metody make_request, bo to za dużo bezsensownej roboty. Zamiast tego skorzystaj z metod w Hydrze do stubbowanie poszczególnych zapytań http - https://github.com/dbalatero/typhoeus

[code]hydra = Typhoeus::Hydra.new
response = Response.new(:code => 200, :headers => “”, :body => “{‘name’ : ‘paul’}”, :time => 0.3)
hydra.stub(:get, “http://localhost:3000/users/1”).and_return(response)

request = Typhoeus::Request.new(“http://localhost:3000/users/1”)
request.on_complete do |response|
JSON.parse(response.body)
end
hydra.queue request
hydra.run[/code]

Hej,

gdy testuje metode

post :serialowy_swiat, :param1 => @param1, :param2 => @param

make_request korzysta z url ktore nie chcialbym wywolywac podczas testowania, dlatego chcialbym stubowac metode make_request. Mam kilka metod ktore korzystjaja z metody make_request.

Czy musze nadpisac ta metode w w tescie funkcjonalnym? Jest taka koniecznosc?

Jest jakas mozliwosc aby naprzyklad w bloku setup testow funkcjonalnych stubowac ta metode bez koniecznosci jej nadpisywania?

Metoda ta zwraca 3 wartosci:

render :nothing => true
redirect
render :text

Caly czas podczas stubowania tej metody dostaje komunikat:

ActionView::MissingTemplate: Missing template]

nie rozumiem dlaczego, nawet jesli testowana metoda nie zwraca zadnego widoku a przekierowywuje na inna strone

[quote=wlodi]Metoda ta zwraca 3 wartosci:

render :nothing => true
redirect
render :text[/quote]
Ta metoda nie zwraca wartosci tylko wykonuje te polecenia. Jesli ja stubujesz to właściwie nic się w kontrolerze nie dzieje i dlatego probuje renderować domyslny widok.

Spróbuj uprościć make_request w ten sposob, że albo zwroci url na ktory ma byc redirect albo rzuci ospowiedni wyjatek. Pózniej ten wyjatek obsłuż za poca rescue_from.

Pozatym nie jestem przekonany czy make_request powinna byc kontrolerze. Może powinna byc w jakims oddzielnym modelu (cos w rodzaju proxy). Dzieki temu łatwiej tez bedzie ja przetestowac

Probuję w tens sposób:

[code]setup do
@param1 = 1111
@param2 = 1111323231113232
@controller = SerialowyController.new
@controller.stubs(@controller.send(:make_request, ‘http://localhost.com’, {:param1 => @param1, :param1 => @param1})).returns(:render)
end

should 'post serialowy swiat' do
  post :serialowy_swiat, :param1 => @param1, :param2 => @param2
  assert_response :success
end

end # ipsos[/code]
To co dostaje na wyjściu:

[code]Started

GET /?offer_id=1111&transaction_id=1111323231113232 HTTP/1.1
Host: localhost.com
Accept: /
Accept-Encoding: deflate, gzip
User-Agent: Typhoeus - http://github.com/dbalatero/typhoeus/tree/master

  • Recv failure: Connection reset by peer
  • Expire cleared
  • Closing connection #0
    E
  1. Error:
    test: posts_serialowy_swiat should post serialowy_swiat. (SerialowyControllerTest):
    RuntimeError: ActionController::RackDelegation#status= delegated to @_response.status=, but @_response is nil: #<SerialowyController:0xb4383ec @action_has_layout=true, @view_context_class=nil, @_headers={“Content-Type”=>“text/html”}, @_status=200>
    app/controllers/serialowy_controller.rb:161:in block in make_request' app/controllers/serialowy_controller.rb:174:inmake_request’
    test/functional/serialowy_controller_test.rb:11:in `block (2 levels) in class:SerialowyControllerTest’[/code]
    Po czesci jest dobrze, metoda make_request korzysta z mojego testowego url ale wciaz zwraca mi blad.

Co wg ciebie robi ta linijka:

@controller.stubs(@controller.send(:make_request, 'http://localhost.com', {:param1 => @param1, :param1 => @param1})).returns(:render)

Nadpisalem metode make_request:

[code]def make_request(url, request_params, landing_page = false)
hydra = Typhoeus::Hydra.new
response = ActionController::TestResponse.new(:code => 200, :headers => “”, :body => “{‘name’ : ‘paul’}”, :time => 0.3)
hydra.stub(:get, “http://localhost:3000/users/1”).and_return(response)
request = Typhoeus::Request.new(“http://localhost:3000/users/1”)
request.on_complete do |response|

  if response.success?

    log_action("Server response: #{response.body}")
    landing_page.blank? ? (render :nothing => true) : (redirect_to landing_page)

  elsif response.timed_out?

    log_action("Server Response URL got a time out")
    render :text => 'Server got a time out', :status => 401

  elsif response.code == 0

    # Could not get an http response, something's wrong
    log_action("#{response.curl_error_message}", :warn)
    render :text => response.curl_error_message, :status => 401

  else

    # Received a non-successful htpp response.
    log_action("HTTP request failed: #{response.code.to_s}", :warn)
    render :text => response.code.to_s, :status => 401

  end
end 
hydra.queue(request)
hydra.run

end[/code]
Ale wyrzuca mi blad:

NoMethodError: undefined method `request=' for nil:NilClass test/functional/serialowy_controller_test.rb:38:in `make_request' app/controllers/serialowy_controller.rb:34:in `ipsos' test/functional/serialowy_controller_test.rb:52:in `block (2 levels) in <class:SerialowyControllerTest>'
Jesli chodzi o ta linijke to jest to zupelnie bezsensowne to co zrobilem.

Ok, udalo sie nadpisac metode make_request:

Poczatek nadpisanej metody

@url = url @url = 'http://127.0.0.1/' hydra = Typhoeus::Hydra.new response = ActionController::TestResponse.new(:success)

Ten kod jest mega-podejrzany. Po co używasz Typhoeus i kolejkujesz requesty w kolejce, jeśli robisz tylko jeden request i tak? Po co korzystać z hydry w tym wypadku?

Poza tym, jakbyś sobie zrefaktorował kod, że Hydra byłaby widoczna poza metodą make_request, to mógłbyś sobie wygodnie stubować requesty prostym:

hydra.stub(:get, "http://localhost:3000/users/1").and_return(response)

A nie, tak jak teraz, musisz całą metodę nadpisywać. Generalnie jest taka zasada, że jak kod się trudno testuje, to pewnie coś z kodem jest nie tak.

czesc, w rzeczywistosci musze ta metode wyrzucic z kontrolera i stworzyc ja modelu. Jak wygenerowac model bez tworzenia migracji w Rails?

  1. Utwórz plik i wypełnij zawartością
  2. Patrz punkt 1.

ok mam :slight_smile:

[code]rails g model --help
Usage:
rails generate model NAME [field:type field:type] [options]

Options:
-o, --orm=NAME # Orm to be invoked

Runtime options:
-f, [–force] # Overwrite files that already exist
-p, [–pretend] # Run but do not make any changes
-q, [–quiet] # Supress status output
-s, [–skip] # Skip files that already exist

Description:
Create rails files for model generator.[/code]

To też jest opcja :slight_smile: Fajnie, że sam znalazłeś ale tak na przyszłość to rails nie robi tutaj żadnej magii. Po prostu tworzysz plik i masz model. Jeśli chcesz model bez migracji (czyli pewnie też bez bazy) to nie dziedziczysz z AR::Base i tyle.