Forum: Ruby on Rails Functional test confusion

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Jeremy M. (Guest)
on 2006-03-30 09:21
I have been reading about testing in RoR for what seems like hours now
in search of the answer to what is probably a simple problem. Where is
the best place to test the second action explained below?

I have a controller (NetworkingController) with a method
(create_network_segment) that makes use of two models (NetworkSegment
and NetworkIpaddress). This particular method does two actions:

1. Create a new NetworkSegment from the submitted form data
2. Create one NetworkIpaddress for each value of a range

class NetworkingController < ApplicationController
  def create_network_segment
    # Example attributes = subnet: 192.168.1.0; netmask: 255.255.255.0
and
    # range: 1..253
    @network_segment = NetworkSegment.new(params[:network_segment])
    if @network_segment.save
      @network_segment.ip_range.each do |ip|
        NetworkIpaddress.create(:network_segment_id =>
@network_segment.id,
                                :octet4 => ip)
      end
      flash[:notice] = 'Network segment was successfully created'
      redirect_to :action => 'show'
    else
      render :action => 'new'
    end
  end
end

I have been writing a functional test but am very confused. I have
defined one network_segment fixture. Here is my test:

  def test_create_network_segment_with_valid_input
    puts NetworkSegment.find(:all).size
    post :create_network_segment, :network_segment => {
                                    :subnet => {
                                      :octet1 => '129',
                                      :octet2 => '83',
                                      :octet3 => '10',
                                      :octet4 => '0' },
                                    :netmask => {
                                      :octet1 => '255',
                                      :octet2 => '255',
                                      :octet3 => '254',
                                      :octet4 => '0' },
                                    :range_start => '10',
                                    :range_end => '100'}
    assert_response :success
    puts NetworkSegment.find(:all).size
  end

It seems that creating a new network_segment in my test is not working.
Yet, I am not sure why.

$ ruby test/functional/networking_controller_test.rb
Loaded suite networking_controller_test
Started
1
1
.
Finished in 0.203078 seconds.

1 tests, 1 assertions, 0 failures, 0 errors

$ tail -6 log/test.log
Processing NetworkingController#create_network_segment (for 0.0.0.0 at
2006-03-30 00:39:16) [POST]
  Session ID:
  Parameters: {"network_segment"=>{"netmask"=>{"octet1"=>"255",
"octet2"=>"255", "octet3"=>"254", "octet4"=>"0"}, "range_start"=>"10",
"range_end"=>"100", "subnet"=>{"octet1"=>"129", "octet2"=>"83",
"octet3"=>"10", "octet4"=>"0"}}, "action"=>"create_network_segment",
"controller"=>"networking"}
  SQL (0.001979)   PRAGMA table_info(network_segments)
Completed in 0.00757 (132 reqs/sec) | Rendering: 0.00014 (1%) | DB:
0.00317 (41%) | 200 OK
[http://test.host/networking/create_network_segment...]
  NetworkSegment Load (0.002151)   SELECT * FROM network_segments

My assumption is that functional tests are used to test the actions I
have been trying to implement in my controller. Once I can test for a
successful save to the database I'll try to move on to testing for the
addition of the network_ipaddresses to the database.

My apologies if this post is confusing. Any help is greatly appreciated.

-Jer
Tim C. (Guest)
on 2006-03-30 10:53
(Received via mailing list)
Hi Jeremy,

If I was doing this I would move the NetworkIPAddress create block down
into
the model of NetworkSegment as perhaps a method call in the :after_save
callback of Network Segment, for two reasons:

1)  This action seems to belong more to the model than it does the
controller.  I'm assuming anytime you create network segment you then
want
these NetworkIPaddress to be created.  By moving the block down into the
Network Segment class you'll be able to have this piece of code run
anytime
you create a NetworkSegment, this may come in handy later if you want to
do
the same thing in another method.  Most importantly though if the
creation
of the NetworkIPAddresses is part of Network Segment it's the
responsibilty
of Network Segment to handle this.  (This get's into better Object
Oriented
design and it's up to you to decide if this is right not).

2)  Moving this function down into the NetworkSegment model makes it a
lot
easier to test using unit tests instead of functional tests, functional
tests can be clumsy when it comes to granularly inspecting variable
contents
as that is not what they are intended to do, unit tests work better for
this, I tend to use functional test to check if things got rendered and
redirected correctly, I never place important business logic in either
the
controller or in functional tests.  In essence I prefer to keep my
controllers dumb and my models smart.  (But in the real world I tend
towards
doing the inverse, I mean is there such thing as a smart model?  Using
Tyra
Banks as an example, I have to say no.)

Moving the block down into the model might give you the ability to test
without having to use the 'put' call (which really isn't a test), and
also
ease pain you might experience down the line by having it in the
controller.

HTH,

Tim C.
removed_email_address@domain.invalid
Jeremy M. (Guest)
on 2006-03-30 20:54
That is exactly what I needed to do! Thanks Tim for the great
suggestion.
This topic is locked and can not be replied to.