Home > Enterprise >  how do I test a private method on controller, using minitest?
how do I test a private method on controller, using minitest?

Time:09-22

Very new to testing

I have a model-less rails app with a controller called "PokerController"

in poker_controller.rb, I have a private method that looks like this:

  private

  def test(x)
    1   x
  end

Then I have a file called 'poker_controller_test.rb' in test/controllers

I'm trying to do something like this:

require 'test_helper'

class PokerControllerTest < ActionController::TestCase

  test "check if test == 2" do
    test = test(1)
    assert test == 2
  end

end

As you can see, I'm trying to save the result of the function 'test' being called, to a variable called 'test' then I'm checking to see if that == 2.

Basically, I'm trying to pass in a number (in this case '1') to the test method, and I want the test to add 1 to 1, and expect to get 2.

I'm sure I'm just not setting up the test right, but how do I call a custom method like this and then evaluate what's returned?

Here's my result from the error in the test:

Error:
PokerControllerTest#test_check_if_test_==_2:
ArgumentError: unknown command "\x01"
    test/controllers/poker_controller_test.rb:6:in `test'
    test/controllers/poker_controller_test.rb:6:in `block in <class:PokerControllerTest>'

CodePudding user response:

You don't.

Testing private methods in general is frowned upon*.

In Rails you mainly test controllers through integration tests. These are tests that send real HTTP requests to your application and then you write assertions about the response or the side effects of sending the request.

"[...] You can test what cookies are set, what HTTP code is returned, how the view looks, or what mutations happened to the DB, but testing the innards of the controller is just not a good idea."
- David Heinemeier Hansson

An example of an integration test is:

require "test_helper"

class PokerControllerTest < ActionDispatch::IntegrationTest
  test "can see the welcome page" do
    get "/path/to/somewhere"
    assert_select "h1", "Welcome to my awesome poker app"
  end
end

If you have a method that you want to test in isolation it does not belong in your controller in the first place and arguably it should not be a private method either.

You should test the public API of your objects. The public API of a controller is the methods that respond to HTTP requests via the router.

The use of ActionController::TestCase is discouraged outside of legacy applications.

New Rails applications no longer generate functional style controller tests and they should only be used for backward compatibility. Integration style controller tests perform actual requests, whereas functional style controller tests merely simulate a request. Besides, integration tests are as fast as functional tests and provide lot of helpers such as as, parsed_body for effective testing of controller actions including even API endpoints.

Besides that the issues with your test is that you're calling the test method on the instance of ActionController::TestCase and not your controller. You're then shadowing the method by defining an instance variable with the same name which is rarely a good thing.

Even if you did call the method on the controller Ruby would still raise an error since you're calling a private method from outside the object - thats the whole point of private methods.

While you could violate encapsulation by calling @controller.send(:test) this is just a bad idea on so many levels.

  • Related