Functional test confusion

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?network_segment=netmaskoctet40octet1255octet2255octet3254subnetoctet40octet1129octet283octet310range_start10range_end100]
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

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.
[email protected]

That is exactly what I needed to do! Thanks Tim for the great
suggestion.