How to write and inherit from an abstract subclass of ActionController :: TestCase

I have a bunch of Rails 3.1 controllers that have very similar testing requirements. I extracted the general code (all Test :: Unit style), for example. The following three tests can be completely repeated for all of them:

def create new_record = { field_to_update => new_value } create_params = { :commit => "Create", :record => new_record } post :create, create_params end test "should_not_create_without_login" do assert_no_difference(count_code) do create; end assert_need_to_log_in end test "should_not_create_without_admin_login" do login_as_non_admin assert_no_difference(count_code) do create; end assert_needs_admin_login end test "should_create" do login_as_admin assert_difference(count_code) do create; end assert_redirected_to list_path end 

and I decided that it could go in an abstract class that inherits from ActionController::TestCase . Then each functional test would only have to redefine abstract methods, ending with a pleasant small and clean, for example.

 class Admin::AvailabilitiesControllerTest < Admin::StandardControllerTest tests Admin::AvailabilitiesController def model ; Availability end def id_to_change ; availabilities(:maybe).id end def field_to_update; :value end def new_value ; 'maybe2' end def list_path ; admin_availabilities_path end end 

However, when I try to do this, it seems that the environment is trying to run the test methods directly from the abstract class, and not from the inherited class:

 E =================================================================================================== Error: test_should_not_create_without_login(Admin::ControllerTestBase): NoMethodError: undefined method `model' for test_should_not_create_without_login(Admin::ControllerTestBase):Admin::ControllerTestBase test/lib/admin_controller_test_base.rb:7:in `count_code' test/lib/admin_controller_test_base.rb:68:in `block in <class:ControllerTestBase>' =================================================================================================== 

I heard that other test frameworks and precious stones can serve as a mechanism for metaprogramming tests, so maybe I'm really wrong about that. But I tried a few things and looked at RSpec , coulda , shoulda , context , contest ... and I still don't see a way to achieve what I need. Any ideas? Thanks!

+4
source share
1 answer

I finally figured it out as soon as I realized that this is a general Ruby Test :: Unit request, and not a Rails testing issue, Google instant detection How to inherit an abstract block tests in Ruby? who already had a good answer. Then the only missing element could use syntactic sugar:

 test "something should behave in a certain way" do ... end 

but not

 def test_something_should_behave_in_a_certain_way" do ... end 

I found the answer to this in the ActiveSupport code base itself, under lib/active_support/test_case.rb :

 extend ActiveSupport::Testing::Declarative 

This module defines test as a class method ( therefore extend is required, not include ).

So, the complete solution looks like this:

 # tests/functional/admin/availabilities_controller_test.rb class Admin::AvailabilitiesControllerTest < ActionController::TestCase tests Admin::AvailabilitiesController include Admin::ControllerTests # non-reusable tests and helper methods specific to this # controller test go here end # lib/admin/controller_tests.rb module Admin::ControllerTests extend ActiveSupport::Testing::Declarative test "this test can be reused by anything which includes this module" do ... end end 

The disadvantage of this modular approach is that you cannot override the included tests. I suppose that just a fundamental limitation of Test :: Unit - maybe the best answer is to switch to RSpec, but I don't know it well enough, but to be sure.

+3
source

Source: https://habr.com/ru/post/1391360/


All Articles