# Quick functional test question

**URL:** <https://www.ruby-forum.com/t/quick-functional-test-question/58764>\
**Category:** Rails\
**Created:** [April 25, 2006, 6:48pm UTC](https://www.ruby-forum.com/t/quick-functional-test-question/58764 "2006-04-25T18:48:30Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![Chris\_T](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/a8b319/32.png) [@Chris\_T](https://www.ruby-forum.com/u/Chris_T)\
**Post date:** [April 25, 2006, 6:48pm UTC](https://www.ruby-forum.com/t/quick-functional-test-question/58764/1 "2006-04-25T18:48:30Z")

</div>

Preamble: I’ve been putting off getting into testing while I got my head  
around everything else, because I am a BAD PERSON, and thought they  
wouldn’t be fun. After the past couple of hours I know I was wrong to  
put it off and right that they wouldn’t be fun (Didn’t help that took me  
a while to realise the Agile Book is out of date on unit testing).

Anyway I have a small method in a controller that parses a release date  
supplied by Amazon into a date field. Took a bit of thinking about the  
best way of doing it but seems to work. however, thought this would be a  
good time to start testing so i can throw all sorts of different inputs  
at it, but the test is not recognizing the method. In the controller  
I’ve got::

class ContributeController \< ApplicationController  
…  
private  
def parse\_amazon\_date(date)  
…  
end  
end

and in my functional test I’ve got:

require File.dirname( **FILE** ) + ‘/…/test\_helper’  
require ‘contribute\_controller’  
…  
def test\_amazon\_date\_parse  
assert\_equal Time.gm(2000, “oct”, 25), parse\_amazon\_date(“25  
October, 2000”)  
#other tests  
end  
end

All I keep getting when i try to run the test is:

NoMethodError: undefined method `parse\_amazon\_date’ for  
#ContributeControllerTest:0x4096aea4

/usr/local/lib/ruby/gems/1.8/gems/actionpack-1.12.1/lib/action\_controller/test\_process.rb:432:in  
`method_missing' test/functional/contribute_controller_test.rb:25:in`test\_amazon\_date\_parse’

Possible I’m being really dense due to a particularly shitty cold, but  
if anyone could point me in he right direction, that’d be great.

---

<div class="post-metadata">

**Author:** ![Chris\_T](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/a8b319/32.png) [@Chris\_T](https://www.ruby-forum.com/u/Chris_T)\
**Post date:** [April 25, 2006, 7:00pm UTC](https://www.ruby-forum.com/t/quick-functional-test-question/58764/2 "2006-04-25T19:00:50Z")

</div>

On Apr 25, 2006, at 12:43 PM, Chris T wrote:

> require File.dirname( **FILE** ) + ‘/…/test\_helper’  
> require ‘contribute\_controller’  
> …  
> def test\_amazon\_date\_parse  
> assert\_equal Time.gm(2000, “oct”, 25), parse\_amazon\_date(“25  
> October, 2000”)  
> #other tests  
> end  
> end

I’m pretty sure that your problem stems from the fact that  
parse\_amazon\_date is a private method of your ContributeController  
class. If you take a look at the top of your functional test file,  
you’ll see that the controller class in required into the functional  
test script. But all that does is make the class and it’s public  
methods available to your test class. That won’t give you outside  
access to a private class method. Tagging a method as private means  
only methods within the parent class can directly call it.

> All I keep getting when i try to run the test is:
> 
> NoMethodError: undefined method `parse_amazon_date' for #<ContributeControllerTest:0x4096aea4> /usr/local/lib/ruby/gems/1.8/gems/actionpack-1.12.1/lib/ action_controller/test_process.rb:432:in`method\_missing’  
> test/functional/contribute\_controller\_test.rb:25:in  
> `test\_amazon\_date\_parse’

Notice how the error message is telling you that it can’t find the  
method you want, inside the test class… This is because it can’t  
see private methods in your controller class. If you want to be able  
to test that method you’ll need to decide on a way for it to be  
accessible through a public interface.

-Brian

---

<div class="post-metadata">

**Author:** ![Chris\_T](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/a8b319/32.png) [@Chris\_T](https://www.ruby-forum.com/u/Chris_T)\
**Post date:** [April 25, 2006, 7:07pm UTC](https://www.ruby-forum.com/t/quick-functional-test-question/58764/3 "2006-04-25T19:07:04Z")

</div>

Just removed the private statement and it’s made no difference. Damn,  
thought that might work

---

<div class="post-metadata">

**Author:** ![Chris\_T](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/a8b319/32.png) [@Chris\_T](https://www.ruby-forum.com/u/Chris_T)\
**Post date:** [April 25, 2006, 8:46pm UTC](https://www.ruby-forum.com/t/quick-functional-test-question/58764/4 "2006-04-25T20:46:47Z")

</div>

I did wonder whether putting it in the controller was entirely the right  
place, but thought it was better there than in the model (since it’s not  
really to do with the business logic), and is only referenced by that  
controller. Haven’t explored custom classes and the lib folder yet, but  
guess it may be time to. Thanks for your help

---

<div class="post-metadata">

**Author:** ![Chris\_T](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/a8b319/32.png) [@Chris\_T](https://www.ruby-forum.com/u/Chris_T)\
**Post date:** [April 25, 2006, 8:06pm UTC](https://www.ruby-forum.com/t/quick-functional-test-question/58764/5 "2006-04-25T20:06:28Z")

</div>

On Apr 25, 2006, at 01:06 PM, Chris T wrote:

> Just removed the private statement and it’s made no difference.  
> Damn, thought that might work

Hmm… OK. I just realized something. You’re not actually calling  
into the controller correctly. Based on your code, I’d say you are  
trying to build your functional test as though it were a unit test.

> > require File.dirname( **FILE** ) + ‘/…/test\_helper’  
> > require ‘contribute\_controller’  
> > …  
> > def test\_amazon\_date\_parse  
> > assert\_equal Time.gm(2000, “oct”, 25), parse\_amazon\_date(“25  
> > October, 2000”)

This statement is more what you would use in a unit test. But even in  
that case, you’d still get an error, since what you’re specifying is  
a method of the current class, not of another class. In reality, I  
think that’s no so bad, since what you’re trying to do doesn’t really  
belong in your controller. Controller methods, aka. actions, are  
there to catch incoming web requests. So when you are doing  
functional testing you actually start the test off by simulating a  
web request, like this:

def test\_my\_silly\_controller  
get :index  
assert\_template ‘silly/index’  
end

This somewhat useless test case calls the index action/method of  
SillyController, like a browser would, and then verifies that the  
controller renders the proper view. It’s somewhat useless, since 95%+  
of the time the proper template is always rendered by your action.

This isn’t at all what you are trying to test here, so what I  
recommend you do is create a custom AmazonDate class. Basically, you  
create an amazon\_date.rb file in your app’s lib directory and put a  
“class AmazonDate … end” in it.

Then you place your class method inside there, like this:

class AmazonDate  
def self.parse (adate)  
…  
end  
end

From this, you can then make a new unit test called  
amazon\_date\_test, where you can then put your normal unit tests to  
verify that your date parser is doing the right things.

-Brian

---

<div class="post-metadata">

**Author:** ![Chris\_T](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/a8b319/32.png) [@Chris\_T](https://www.ruby-forum.com/u/Chris_T)\
**Post date:** [April 26, 2006, 12:33am UTC](https://www.ruby-forum.com/t/quick-functional-test-question/58764/6 "2006-04-26T00:33:22Z")

</div>

Brain  
Had another think about this, and I’m not doubting you’re right just  
trying to understand things a bit better. Are you saying you shouldn’t  
put methods in controllers that aren’t there to catch actions directly -  
i.e. those methods that are just servicing the ‘action’ methods should  
go elsewhere (this doesn’t make 100% sense to me, not least because  
surely the methods in the application controller are never called  
directly)? Or is it that they can’t be tested atomically – only as part  
of the visible action?

Also does seem a bit sledgehammer to crack a nut, when it’s only a  
5-line method. I suppose the alternative is to test the method  
indirectly, through passing various fixtures through the visible case,  
though this strikes me as a slightly less pure way of doing it. Still  
not quite understanding it…

---

<div class="post-metadata">

**Author:** ![Chris\_T](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/a8b319/32.png) [@Chris\_T](https://www.ruby-forum.com/u/Chris_T)\
**Post date:** [April 26, 2006, 9:37am UTC](https://www.ruby-forum.com/t/quick-functional-test-question/58764/7 "2006-04-26T09:37:29Z")

</div>

OK. I think I understand where you’re coming from. I think it’s one of  
those things that, coming from a non-OO background takes a bit of  
getting used to. It’s particularly difficult when you’ve done the  
classic newbie route like I have – coming from PHP, trying the rails  
tutorials, then reading the Agile book, only after then starting to  
learn Ruby (and no OO experience at all).

In cases like this, it’s doubly difficult, because there are lots of  
ways the parsing could have been incorporated into the program (even  
though there may only be one correct OO way): I could quite easily have  
incorporated the parsing of the Amazon date into the action (as that’s  
the only place it’s used), or could have incorporated it into a view,  
possibly via a helper (because the resulting Date object is used only to  
populate a date select field), or could incorporate it into the Book  
model as an instance method, as getting a correct Book object is the  
final goal.

I guess what I’m saying is when you approach this from a non-OO  
viewpoint, there’s a lot of ways to skin this particular cat, all of  
which are superficially easier than this route. However, for what it’s  
worth, when I’ve been forced to go down a true OO route, I’ve tended to  
be grateful in the long run.

Thanks for your help.

---

<div class="post-metadata">

**Author:** ![Chris\_T](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/a8b319/32.png) [@Chris\_T](https://www.ruby-forum.com/u/Chris_T)\
**Post date:** [April 26, 2006, 2:45am UTC](https://www.ruby-forum.com/t/quick-functional-test-question/58764/8 "2006-04-26T02:45:57Z")

</div>

On Apr 25, 2006, at 06:25 PM, Chris T wrote:

> Had another think about this, and I’m not doubting you’re right  
> just trying to understand things a bit better. Are you saying you  
> shouldn’t put methods in controllers that aren’t there to catch  
> actions directly - i.e. those methods that are just servicing the  
> ‘action’ methods should go elsewhere (this doesn’t make 100% sense  
> to me, not least because surely the methods in the application  
> controller are never called directly)?

Not at all. There’s all kinds of reasons for non-action methods in  
controllers, but none of those reasons should include performing  
business logic on a data object. That business logic is part of the  
object’s behavior, which you should definitely be accessing from the  
controller, but that’s not where the business logic should go.

> Or is it that they can’t be tested atomically – only as part of  
> the visible action?

This is probably a good indication that you are working with an  
object’s behavior and that’s something that should be part of the  
model-layer, in the Rails MVC architecture. Just remember, not all  
“models” have to be based on ActiveRecord.

> Also does seem a bit sledgehammer to crack a nut, when it’s only a  
> 5-line method. I suppose the alternative is to test the method  
> indirectly, through passing various fixtures through the visible  
> case, though this strikes me as a slightly less pure way of doing  
> it. Still not quite understanding it…

I think what you need to do is stop thinking of it as “only a 5-line  
method.” Referring to it that way takes you down the road of  
procedural programming, which you can do, but that’s really not a  
place you want to go.

You’ve got a business object, AmazonDate, that you need to operate  
on. Actually, re-reading the description in your OP, it actually  
looks like what you need is a way to build a standard Ruby Date from  
a custom supplied string representation. You should probably do this,  
and this might be “more correct”, as an extension of the standard  
Ruby Date class. Something along these lines:

class Date  
def self.from\_amazon\_date(amazon\_date)  
… # your parsing statements, making sure you return a Date object  
end  
end

Again, I would place this into a script file, called something like  
amazon\_date.rb, in the top-level of your app’s lib folder. What we’re  
doing here is specifying a custom behavior, within a standard Ruby  
class. These kinds of dynamic class extensions happen all throughout  
Rails and I think is the right fit for what you’re looking to do…

-Brian
