Getting output from cfdump with the plugin

43 views
Skip to first unread message

Bob Silverberg

unread,
Dec 9, 2008, 9:45:20 PM12/9/08
to mxu...@googlegroups.com
I've been really enjoying working with the mxunit eclipse plugin, but
there's one thing that I cannot seem to figure out. I hope that I'm
just missing something and someone on the list can show me how easy it
is.

I know that I can get a cfdump of any variable from within my test
method using the debug() function, but sometimes I want to put a
cfdump inside the actual method that I'm testing. I know, with true
TDD there would be no need for this, but I am often refactoring old
code and end up with some methods that are pretty complex. Before I
started using the plugin to run my tests I'd just stick a cfdump +
cfabort in my method, run the app in a browser and see my dump output.
If I try to do this and run a test using the plugin I cannot see the
actual output of the cfdump.

My workaround thus far is to change the actual method that I'm
testing, return whatever it is I want to dump from the method, and
then use debug() on that returned value in my test method. But I
really don't like doing that.

Does anyone have any suggestions of how to do this more easily? If
not, is this something that could be achieved through changes to the
plugin code?

Thanks,
Bob

--
Bob Silverberg
www.silverwareconsulting.com

Marc Esher

unread,
Dec 9, 2008, 10:06:45 PM12/9/08
to mxu...@googlegroups.com
Bob,
Excellent question and I still find myself fighting with it from
time to time. I had a short conversation with the Farrars a while back
about this but then dropped it. I do not believe this is a plugin
question... I'd be surprised if you got output when running it in the
browser, too, using the browser test runner.

Bottom line: there's not gonna be a "native, easy" way to do this if
your components have output="false" on them. In addition, if you have
the dumps in your functions, even with output="true", you won't see
the dumps if the test itself fails.

So I say that if you need to see your data, then you just ain't
hardcore enough. Embrace the pain of TDD, Bob!

Or, maybe there is a better way. See, what i've been toying with is
the ability to inject "debug()" itself into components under test.
this would enable you to simply call debug(mydata) from within your
components as if debug were a function in that component. then, it'd
behave exactly as debug does within the tests.

There are downsides: 1) it's bound to happen that you forget to
take out those calls to debug, and then when the code runs "for real",
it'll fail. 2) you'll need to actively inject debug into components
under test: setup(){ obj = createobject; injectDebug(obj);} 3)
purists will call you all sorts of mean names and probably not eat
lunch with you at conferences. if they do, they'll snicker when you
get up to whizz. 4) this is probably the biggest: any components
that already have a function named "debug" will need to have a
different way of injecting debug. so possibly something like
injectDebug(obj,"__debug") to provide an alternate name for the
function.

All of this would require some work on the mxunit side to make it
happen, obviously, and we'd want to rename the internal debug array to
make it "safe", i.e. have the array not collide with potential
variable names already existent in components under test. Not a
terribly big deal I'd say, though. Bill doesn't mind.

Thoughts? Anyone else out there think this is good, terrible, don't care?

Bob Silverberg

unread,
Dec 9, 2008, 10:54:44 PM12/9/08
to mxu...@googlegroups.com
Marc,

Thanks for taking my hair-brained scheme seriously ;-)

I like your idea of injecting debug() into the component under test.
That's kind of what I was hoping to be able to do: to dump some data
from within the method being tested and have it show up in the final
debug output of the plugin. I understand the downsides that you
describe, but hey, I'm willing to take the risk if you guys can make
it happen. I can withstand the snickers.

Having said that, I'd love to be able to do this without having to
specify that "injection" every time I need it. Is it within the realm
of possibility to have that happen automatically? Maybe via a global
setting that I could configure in my base test case (to mitigate
downside #4 to which you allude)? Speaking of downside #4, another
way to mitigate that might be to give the method an "unusual" name by
default (e.g., ___debug()).

Thanks for taking the time to consider this, and thanks for the latest
update to the plugin. I just read your post today about it. I didn't
realize that you were actually going to implement the timeout thing
that we discussed, so thanks for that, and for the kind words.

Cheers,
Bob
--
Bob Silverberg
www.silverwareconsulting.com

denstar

unread,
Dec 10, 2008, 5:03:41 AM12/10/08
to mxu...@googlegroups.com
I don't know if there would be any easy way to automatically inject
debug() into any random object under test, as you may have something
like:

someService.getSomeComponent()

and automagically injecting debug into any object however far down the
chain seems neigh improbable. It's late here tho, so I may be missing
some nifty way of achieving something like that.

At any rate, you *can* do a <cfdump.../><cfabort /> and view the
output from your dump, if you're using the html runner.

I'm not sure if capturing that dump is possible for the plugin, tho.
I actually took a look at what was going on under the mxu hood there,
months ago (because I'm lazy and didn't like switching to a
web-browser to do my -- yes, not quite TDD-ish -- random variable
dumping) and for some reason it didn't seem like getting the output
before an abort, into the plugin view, was a simple thing.

But that was some randomness, and I don't recall really what I found out.

But for what it's worth, you can dump and then abort right away, to
see the dump output (even in output=false blocks), if you're running
it in a browser. At least on Railo (tho I'm pretty sure CF works the
same).

I love the idea of being able to inject debug() into objects tho, that
would be the bee's knees, I reckon.

Even if it's sorta anti... It is useful. =]

:Denny

--
Sentences are not as such either true or false.
J. L. Austin

Marc Esher

unread,
Dec 10, 2008, 5:48:24 AM12/10/08
to mxu...@googlegroups.com
I have two additional thoughts here:

1) cfabort won't work. but cfexit will.

take this:

<cffunction name="doSomethingThenExitToGetDump" output="true">
<cfdump var="#StructNew()#">

<cfexit method="exittemplate">

<cfthrow message="you ain't gonna see that struct">
</cffunction>


Again, though, output=true must be on.


2) I can actually think of a way of auto-injecting debug such that it
could be controlled with a setting. I'll play around a bit and see if
my suspicions on an approach for this will actually work.

marc

Bob Silverberg

unread,
Dec 10, 2008, 7:55:37 AM12/10/08
to mxu...@googlegroups.com
Cool. Are you saying that, no matter how it ends up being
implemented, it will only work with output="true"? It would be nice
to not have to change that setting in the method, but I guess I can't
ask you to do the impossible ;-)

Bob
--
Bob Silverberg
www.silverwareconsulting.com

Timothy Farrar

unread,
Dec 10, 2008, 8:24:23 AM12/10/08
to mxu...@googlegroups.com
I think that the best solution might be to use the cf8 step debugger in eclipse. This way, you can see the values of different variables at different points in your code, without having to modify your methods. I understand the need / desire for injecting the debug method (I've wanted to do it a number of times myself), but I think that we sort of put at risk the whole concept of unit testing when we do this.

Just my current take on the topic,

Timothy Farrar

Marc Esher

unread,
Dec 10, 2008, 8:25:22 AM12/10/08
to mxu...@googlegroups.com
no, with the injected debug it'd work either way.

just the cfexit exittemplate approach (so you can do what you want to
do right now, without cfabort) will require output=true.

On Wed, Dec 10, 2008 at 7:55 AM, Bob Silverberg
<bob.sil...@gmail.com> wrote:
>

Bob Silverberg

unread,
Dec 10, 2008, 8:30:46 AM12/10/08
to mxu...@googlegroups.com
Ah! So you're saying that right now, with no changes to the plugin,
if I use output="true" and cfexit I'll see my dumped output in the
final debug output? Sorry, I know I could just test this myself, but
I'm in the middle of getting two kids ready to go to school ;-)
--
Bob Silverberg
www.silverwareconsulting.com

Marc Esher

unread,
Dec 10, 2008, 8:35:15 AM12/10/08
to mxu...@googlegroups.com
that's funny Bob. otherwise i'd have written "just test it yourself". :-)

yes, that's what i'm saying. I did it this morning at home before
leaving for work and it worked fine.

good luck!

On Wed, Dec 10, 2008 at 8:30 AM, Bob Silverberg

Marc Esher

unread,
Dec 10, 2008, 8:44:48 AM12/10/08
to mxu...@googlegroups.com
Tim, good to hear from you!

In part, that's kind of why I let the whole injected debug thing
drop... because i use the step debugger. But the thing is, at least in
my experience, when I *really* want injected debug isn't in the
day-to-day stuff where it's just strings and simple things. it's when
i'm working with queries and big structs. step debug is pretty much
useless for queries, and it outgrows its usefulness really quickly
when you start getting big nested structures/arrays.

The timing for Bob's email is interesting for me personally because in
the past few weeks I've found myself in Bob's boat a lot. The "itch"
for an injected debug is getting worse.

I've thought a lot about this, and I fail to see how this compromises
the idea of unit testing. In fact, this thinking -- I think -- is part
of the reason so many people avoid unit testing and opt for "tst" cfm
files... because at the end of the day, *while* you're developing
something, you do not serve yourself well when you try to code in a
black box. If your functions have data, they have it for a reason. and
if you're trying to do something with that data, especially when
you're just starting out with the development of said function, you
gotta see how it morphs over time. Like I said, for strings, this is
easy in a debugger. but not so for complex data types. the
cfdump/cfabort method of coding is absolutely valid, and here's a case
for me where if your gut says "yes, this is the fastest way to get
from A to B, well.... I listen to my gut. And my gut says that simply
dumping out a struct and scanning to where i know i need to go will be
a whole lot faster than trying to watch it in a step debugger.

To me, unit testing, above all, is like a friend helping me code. it's
not mine enemy, and if it starts making my life harder, then it's not
so much my friend anymore. To put it another way, when I'm in front
of my machine, coding, I'm frickin' batman baby. And I want the
baddestass stuff in my bat belt. I might not need the
scale-a-tall-building-repeller-thingamajiggie every day, but when I
do, the thing better be there. Every time i have to drop out of a
unit test and into a .cfm file just to do a cfdump, unit testing has
failed me.

I understand and respect and value your opinion, Tim, and I'm glad you
chimed in on this topic because I was trying to remember John's
opposition to the injected debug concept and now I remember. But
here's the thing: I'm getting old, and I'm starting to understand that
I'm not smart enough or powerful enough or influential enough to
"compromise the whole idea" of anything in this world. I just wanna
get stuff done. Tools aren't my master; I'm theirs. The better the
tools, the better work I can do.

marc

Timothy Farrar

unread,
Dec 10, 2008, 8:56:03 AM12/10/08
to mxu...@googlegroups.com
So I wonder if a good solution (since we are injecting the method (mixin style I hope) ) would be to add a blank debug method into the component we are testing, and then override it with the mxUnit debug that we inject....
This seems like a more stable approach to me. The biggest problem I have (and remember that I tend to like the idea of adding the debug method to the components I am testing) is the increased chance for failure that I would get if I accidentally left a debug call in the code that I was testing...

Let me know what you think about this,

Timothy

Marc Esher

unread,
Dec 10, 2008, 9:11:01 AM12/10/08
to mxu...@googlegroups.com
there's a 100% chance of failure if you leave the debug call in, and
that is exactly the behavior I'd want! the point of using the debug
isn't to be there as an ever-lasting artifact. it's to help you see
the data while you're doing TDD. once you get done what you get done,
you remove the call. if you forget, it's going to get found very
quickly in integration testing b/c it's going to error. For me, I
can't stand swallowed errors. I want them front and center.

and i'd much prefer an error during integration testing saying "method
mxunitDebug() not found" than leaving an output="true" on when it
should be false. Where I work, we do a lot of nasty string stuff, and
an output="true" where it needs to be false has led to hours of
frustrating debugging.

i can see someone saying "but the thing is going to happen where you
do your stupid little debug inject thingie, and then you forget to
take it out, and then it goes to production and you get an error". to
that I say, that's a process problem, not a technology problem. if
you're writing code that only gets tested in your IDE and not in your
real app, in the browser (or via integration testing tools), then you
got bigger problems, ones that shouldn't be blamed on the technology.

that said, i don't see why there couldn't be functionality inside
mxunit for setting a flag to NOT inject debug. I have automated cfm
scripts that use directorytestsuite to run all my tests. they run on a
schedule. for them, it'd be sensible to NOT have debug injected so
that if i did leave a call in there, it'd get caught during the
automated run and i'd see it in the email i get.

maybe something like:

<cfset directoryTestSuite.run(....., debug="false")> or something
like that. just thinking out loud, but it's an easy problem to solve.

thoughts?

marc

On Wed, Dec 10, 2008 at 8:56 AM, Timothy Farrar

Timothy Farrar

unread,
Dec 10, 2008, 9:38:13 AM12/10/08
to mxu...@googlegroups.com
Interesting...

I totally understand your point of view on this... problem  with threads like this, is that either way we go with this, we have a greater number of points of failure....

For me, a good solution would be to plan on going back and removing all debug calls, but playing it safe by including an empty debug method that will keep my code from breaking if I miss one.

Marc on the other hand has a bunch of sweet automation cfm scripts that will just catch the error for him, and he will know what to fix and where...

guess it is just another matter of preference....

Oh, and marc... for lazy developers like me, care to share your automation scripts with the rest of us?

I would love to have this some day, and plan to eventually write it, but in the meantime, I'd love to see your code.

just my thought,

Timothy

Marc Esher

unread,
Dec 10, 2008, 9:55:21 AM12/10/08
to mxu...@googlegroups.com
My coldfusion automation scripts are pretty basic. And they're based
entirely on the mxunit/samples/ScheduledRun.cfm file in the mxunit
download. I don't mind sharing them, though with the caveat that I'm
not saying this is "best practice". it's quick and dirty and really
simple. it is not in any way "enterprise-y".

the only difference between mine and that ScheduledRun.cfm file is
that I write the "summary" of the results to a file on each run. and i
read it back in and stuff it in the email that I get sent so that i
can easily compare the numbers without having to look over the test
results. This idea comes from the mxunit build.xml file's "runTests"
target, which does the same thing. My CF scripts simply have a CF
version of the concept. Build.xml is in the download, too, as an
example of how you might use ant to run your mxunit tests and email
the results, with the summary and whatnot.

here's one of my scripts, in all its glory, with just a few things
stripped out. this one runs 3 different directories of tests and spits
out their output. It's pretty low-rent, but I don't mind. When I get
my act together I'll hook this into a CI server and actually store the
results; but for me, for now, this works just fine. I simply have this
file, named "run.cfm", set up as a scheduled task in cfadministrator,
and I override those URL params in the scheduled task URL

<cfsetting requesttimeout="500">

<cfparam name="URL.output" default="extjs">
<cfparam name="url.quiet" default="false">
<cfparam name="url.email" default="false">
<cfparam name="url.recipients" default="????@????.com">

<cfset dir = expandPath(".")>
<cfoutput><h1>#dir#</h1></cfoutput>

<cfset DTS = createObject("component","mxunit.runner.DirectoryTestSuite")>
<cfset DTS2 = createObject("component","mxunit.runner.DirectoryTestSuite")>
<cfset DTS3 = createObject("component","mxunit.runner.DirectoryTestSuite")>

<cfinvoke component="#DTS#" method="run" directory="#dir#\Retail"
recurse="true" returnvariable="RetailResults"
componentpath="blah.blah.Retail">


<cfinvoke component="#DTS2#" method="run" directory="#dir#\Enrollment"
recurse="true" returnvariable="EnrollmentResults"
componentpath="blah.blah.Enrollment">
<cfinvoke component="#DTS3#" method="run" directory="#dir#\Statements"
recurse="true" returnvariable="StatementsResults"
componentpath="blah.blah.Statements">
<cfsetting showdebugoutput="true">

<cfoutput>

<cfset helper = createObject("component","TestHelpers")>
<cfset lastResultsSummary = helper.readRecentResultsSummary(dir)>


<cfsavecontent variable="resultsSummary">

<p><b>Retail</b></p>
<p>Failures: <span
class="failure">#retailresults.getFailures()#</span> Errors: <span
class="error">#retailresults.getErrors()#</span> Successes: <span
class="success">#retailresults.getSuccesses()#</span></p>

<p><b>Enrollment</b></p>
<p>Failures: <span
class="failure">#enrollmentresults.getFailures()#</span> Errors: <span
class="error">#enrollmentresults.getErrors()#</span> Successes: <span
class="success">#enrollmentresults.getSuccesses()#</span></p>


<p><b>Statements</b></p>
<p>Failures: <span
class="failure">#statementsresults.getFailures()#</span> Errors: <span
class="error">#statementsresults.getErrors()#</span> Successes: <span
class="success">#statementsresults.getSuccesses()#</span></p>
<hr>
</cfsavecontent>

<cfset helper.writeRecentResultsSummary(dir,resultsSummary)>

<cfsavecontent variable="recenthtml">
<h2>Summary:</h2>
#resultsSummary#
<h2>Last time:</h2>
#lastResultsSummary#
#retailresults.getResultsOutput(URL.output)#
#enrollmentresults.getResultsOutput(URL.output)#
#statementsresults.getResultsOutput(URL.output)#
</cfsavecontent>

</cfoutput>

<cfif NOT url.quiet>
<cfoutput>#recenthtml#</cfoutput>
</cfif>

<cfif url.email>
<!--- change this 'from' email! --->
<cfmail from="me" to="#url.recipients#" subject="Unit Test Results :
#DateFormat(now(),'short')# @ #TimeFormat(now(),'short')#"
type="html">
#recenthtml#
</cfmail>
</cfif>





On Wed, Dec 10, 2008 at 9:38 AM, Timothy Farrar

Bob Silverberg

unread,
Dec 10, 2008, 8:30:16 PM12/10/08
to mxu...@googlegroups.com
There's a lot to digest since this morning, but I think I can sum up
my opinion as: yes, please allow for automatic injection of debug, and
also allow for that to be turned off via a setting. I think I
suggested the latter earlier in the thread.

Thanks,
Bob
--
Bob Silverberg
www.silverwareconsulting.com

denstar

unread,
Dec 11, 2008, 6:40:05 AM12/11/08
to mxu...@googlegroups.com
A debugger?!?!? "Whole concept of unit testing"?!?!?!?

You, dear sir, are some type of alien.

=]

Seriously tho: I've had those late-nite seshes where I stick that
<cfabort> in there and then fall asleep (monitor bright as day, even).

That's a real bitch, when you wake-up, and forgot you stuck that
randomness there, neh? You're all like "why the hell is this thing
just outputting blankness?". And good luck sorting out the "real"
cfabort amongst the commented-out ones, right?

Yeah, it happened to me once. I was pretty pissed, so it didn't
happen more than once or twice more. :-)).

Even having lived through that-- or, those, experiences, I'm in favor
of an un-pure debug type deal.

But I'm "dirty". =]

--
I find it ironic how far I will go, to be lazy.

Mike Rankin

unread,
Dec 11, 2008, 8:05:12 AM12/11/08
to mxunit
This might be an alternative approach that seems to work with mxunit
for me without modification. I use a base object for most of my
object types, especially ones that are carrying around a lot of data.
In the base object that gets extended, I have a generic print() method
that does a cfdump of my data with output=true. That base object then
gets extended for any class that is roughly the same type (VO, DAO,
etc.). Then in my unit tests, if I need to see some data, I call the
print method in the debug call and that's it.

Marc Esher

unread,
Dec 11, 2008, 10:07:18 AM12/11/08
to mxu...@googlegroups.com
but that won't work when the function calling print has output=false

<cffunction name="printSomething" output="false">
<cfset print("this is data being sent to print from an output=false
function")>
</cffunction>

<cffunction name="print" output="true">
<cfargument name="data" type="any" required="true"/>
<cfdump var="#data#">
</cffunction>

In that case, the string in printSomething won't show up in the output.

Or is that not what you're talking about?

denstar

unread,
Dec 11, 2008, 2:30:52 PM12/11/08
to mxu...@googlegroups.com
I've found that doing something like this in the test setup method:

server.debug = debug;
variables.transactionService = coldSpring.getBean('transactionService');
variables.transactionService.debugarray = this.debugarray;

lets me use server.debug() within my TransactionService component.

It's a total hack job, but seems to work. On Railo at least.

I usually have a dumpvar() in any complex component, that I generally
use to dump>abort from within cfscript and whatnot. If I didn't want
to have errors about missing debug when running outside the harness, I
could stick the debug in there, with a check for existence. That
would be more pure and less dangerous... but I don't mind living on
the edge.

Especially if I get selenium rocking on the dev server. Then I think
I'd actually prefer an error, as I really don't like "forgetting"
where I've got debug() or log() type stuff.

Eh...

The other thought I had was that cfdump content must be stored
somewhere, even if it's not "output"... I wonder if that content is
accessible from the request object somehow? If so, it's probably done
different with each CF engine, but grabbing that content and adding it
to the debug content would be pretty cool, maybe.

Eh.

Random ideas. =]

:denny

--
The existence of law is one thing; its merit or demerit is another.
J. L. Austin

Marc Esher

unread,
Dec 12, 2008, 6:04:11 PM12/12/08
to mxu...@googlegroups.com
i wonder if CF just discards it or actually stores it in some other
buffer somewheres.

Sean Corfield

unread,
Dec 13, 2008, 9:25:19 PM12/13/08
to mxu...@googlegroups.com
On Thu, Dec 11, 2008 at 7:07 AM, Marc Esher <marc....@gmail.com> wrote:
> but that won't work when the function calling print has output=false

But you can use <cfdump var="#whatever#" output="console"/> and have
debug output appear in your terminal console. You do start CF from a
console right? All the CF team tell folks to do this in development
whenever they give presentations at conferences :)

Seriously tho', <cflog ... log="console" /> and <cfdump ...
output="console" /> are two very useful debugging tools when working
with CFC-based applications.

Assuming you don't want to use the incredible CF8 Eclipse debugger, of course...
--
Sean A Corfield -- (904) 302-SEAN
An Architect's View -- http://corfield.org/

"If you're not annoying somebody, you're not really alive."
-- Margaret Atwood

Marc Esher

unread,
Dec 14, 2008, 7:12:56 AM12/14/08
to mxu...@googlegroups.com
On Sat, Dec 13, 2008 at 9:25 PM, Sean Corfield <seanco...@gmail.com> wrote:
>
> On Thu, Dec 11, 2008 at 7:07 AM, Marc Esher <marc....@gmail.com> wrote:
>> but that won't work when the function calling print has output=false
>
> But you can use <cfdump var="#whatever#" output="console"/> and have
> debug output appear in your terminal console. You do start CF from a
> console right? All the CF team tell folks to do this in development
> whenever they give presentations at conferences :)
>
> Seriously tho', <cflog ... log="console" /> and <cfdump ...
> output="console" /> are two very useful debugging tools when working
> with CFC-based applications.


For me -- and this is possibly just a function of the nature of work I
find myself doing a fair amount of time (big data structures), the
console and cflog solutions suffer from the same problem as the
debugger: they don't scale as a debug aid. it'd be like looking at 100
lines of json.... yeeeeesh. Like, if I were debugging json across the
wire for an ajax app, returning maybe 100 rows or something, I
wouldn't even want to try it without using firebug and the tree view
for seeing the json as an object.

call it laziness or tired eyes. Whatever it is, it slows me down. And
that just won't do!

billy

unread,
Dec 14, 2008, 7:47:38 AM12/14/08
to mxunit
Maybe passing around a Collecting Parameter or Listener object might
work, and then revamping the actual debug output to not use cfdump,
but some more efficient format that still presents the data needed.
This still could present problems with large objects, but might be
worth a shot ... I do think that having a configurable debug mechanism
would be valuable; diff++.

bill

On Dec 14, 7:12 am, "Marc Esher" <marc.es...@gmail.com> wrote:
> On Sat, Dec 13, 2008 at 9:25 PM, Sean Corfield <seancorfi...@gmail.com> wrote:
>
> > On Thu, Dec 11, 2008 at 7:07 AM, Marc Esher <marc.es...@gmail.com> wrote:
> >> but that won't work when the function calling print has output=false
>
> > But you can use <cfdump var="#whatever#" output="console"/> and have
> > debug output appear in your terminal console. You do start CF from a
> > console right? All the CF team tell folks to do this in development
> > whenever they give presentations at conferences :)
>
> > Seriously tho', <cflog ... log="console" /> and <cfdump ...
> > output="console" /> are two very useful debugging tools when working
> > with CFC-based applications.
>
> For me -- and this is possibly just a function of the nature of work I
> find myself doing a fair amount of time (big data structures), the
> console and cflog solutions suffer from the same problem as the
> debugger: they don't scale as a debug aid. it'd be like looking at 100
> lines of json.... yeeeeesh. Like, if I were debugging json across the
> wire for an ajax app, returning maybe 100 rows or something, I
> wouldn't even want to try it without using firebug and the tree view
> for seeing the json as an object.
>
> call it laziness or tired eyes. Whatever it is, it slows me down. And
> that just won't do!
>
>
>
> > Assuming you don't want to use the incredible CF8 Eclipse debugger, of course...
> > --
> > Sean A Corfield -- (904) 302-SEAN
> > An Architect's View --http://corfield.org/

Bob Silverberg

unread,
Dec 14, 2008, 7:58:53 AM12/14/08
to mxu...@googlegroups.com
I found Denny's hack interesting, so I tried it, but it doesn't work
for me. Could it be a problem with CF vs Railo (I doubt it)? Maybe
I'm misunderstanding how to implement it. Here's what I'm doing:

In my basetestcase.cfc, in a method that always gets called, I'm doing:

<cfset server.debug = debug />

Then, in my concrete test case:

<cfset ValidationFactory = getBeanFactory().getBean("ValidationFactory") />
<cfset ValidationFactory.debugarray = this.debugarray />

And in ValidationFactory.cfc:

<cfset server.debug(variables.instance) />

I'm not getting any errors, but I'm also not seeing the results of
that last call to debug() in my debug output.

Am I misunderstanding how to get this to work? Am I missing a step?
I can see how this could be quite useful to me as I could incorporate
most of it into my basetestcase, and then be able to call
server.debug() in any component under test.

Cheers,
Bob


On Thu, Dec 11, 2008 at 2:30 PM, denstar <vallia...@gmail.com> wrote:
>
--
Bob Silverberg
www.silverwareconsulting.com

denstar

unread,
Dec 14, 2008, 2:27:51 PM12/14/08
to mxu...@googlegroups.com
Hmmm... I wouldn't put it past me to leave something out, or have left
the function on "output=true" ;-), but this time, well, it seems to
still be working as advertised for me.

Here is the test I was using to, um, test the idea (a test and a component):

http://coldfusion.pastebin.com/me07eb42

Check that out and if it doesn't work, I guess we chalk it up to a
difference between railo and adobe cf.

HIH!

:D

--
That whose existence is necessary must necessarily be one essence.
Avicenna

Marc Esher

unread,
Dec 15, 2008, 8:32:18 AM12/15/08
to mxu...@googlegroups.com
All,
If you're interested in seeing the automatic debug injection in
action, here's what to do. this assumes you're familiar enough with
subversion to get this all working.

1) point your mxunit project to subversion at
http://mxunit.googlecode.com/svn/mxunit/branches/marcdebuginjectplay
2) open up mxunit/PluginDemoTests/DebugOutputTest.cfc and run it.
3) Open up the browser view results for the test. You'll see stuff
added into the debug array... but you won't see those calls in the
Test itself
4) open up mxunit/PluginDemoTests/SomeObject.cfc and check out the
trustDebugIsInjected function. note the calls to "mxunitdebug()"

This was a super duper quick proof of concept. All the code is inlined
in TestSuite.cfc and in real life, that isn't how it'd go down I
suspect. In reality, this sort of thing would be done with a series of
interceptors that bill and i have been talking about for the next
major version of mxunit. Regardless of implementation, the gist is
this:

1) after TestSuite invokes setup on a given test case, inject mxunit's
built-in ComponentBlender functions to make mixin stuff easier
2) get a list of all variables in the TestCase after setup is invoked
3) loop over those variables and, based on some simple conditions (is
the variable an object? is it not named "this"? some others would
certainly follow), inject several functions into the variable. Then,
set the debug array into the variable

that's pretty much it. if you want to see the code, it's in
TestSuite.cfc around line 165.

Also, in real life, the conditions for injecting this junk would be
more involved.

One key thing I had to do, which is transparent to all calling code,
was to turn the internal debug array into a structure containing an
array. This enables the debug struct to be passed from TestCase into
the variables (objects under test) by reference.


Again, this is proof of concept. It doesn't look at any config params,
and there's no functionality for turning off the injection, which
you'd need for automated tests etc (i.e. you want your automated tests
to NOT have stuff injected so that calls to mxunitdebug() that you
forgot to take out will error.

feedback welcome.

marc

denstar

unread,
Dec 16, 2008, 3:17:07 PM12/16/08
to mxu...@googlegroups.com
Hey Marc!

With the injection, it looks like we're only getting one level deep
into the object "chain", if you will (no objects created by that
object will have mxunitdebug injected).

I think that we're going to have to get "messy" to really make this as
useful as it should be.

"Messy" meaning I think we're going to have to tap one of those global
scopes-- request or server, probably -- to be able to add a call to
debug from anywhere down the chain (I know there's a gooder word for
"the chain", but I'm drawing a blank).

Instead of using server, I tried the request scope, and after changing
TestCase to store it's "debugArrayWrapper" in the request scope, I was
able to use request.debug() from an object a few levels down.

This made me happy, but I wonder-- well, basically about race
conditions. I don't know how easy it would be to really get this
working, um, in an organized manner, so to speak. Using the request
scope seems like bad form, but, well, it seems to work.

Perhaps some type of introspection/reflection would allow us to inject
into sub-objects, and sub-sub-objects, but it seems harder to control
that than using, say, the request or server scope.

Bah. My head isn't exactly into the problem, but I just wanted to put
these thoughts out there.

--
A special kind of beauty exists which is born in language, of
language, and for language.
Gaston Bachelard

On Mon, Dec 15, 2008 at 6:32 AM, Marc Esher wrote:
>
> All,
> If you're interested in seeing the automatic debug injection in
> action, here's what to do. this assumes you're familiar enough with
> subversion to get this all working.

...

denstar

unread,
Jan 23, 2009, 7:34:19 PM1/23/09
to mxu...@googlegroups.com
Ok, so enabling debug from anywhere may encourage "throw away" coding,
but damnit, it's worth it. =]

I've got a little patch that seems to work like this:

if you set request.debug = this.debug in setUp(), you can do
request.debug(whatever) from any component accessed during the
request.

This is working pretty good for me (tested from within the eclipse
plugin, using Railo), as if I remove or comment out the setUp()
request.debug = this.debug line, I get errors wherever I'm still
calling request.debug.

I think a URL switch might be cleaner (thus defaulting to "off", as
well as negating the need to set request.debug in the test itself-- a
little redundancy for the forgetful ;]), and would allow for adding a
toggle to the eclipse plugin UI pretty easily, perhaps...

I feel that using this shortcut is one step closer to the dark side of
the force... I also feel that it's powerful enough to justify it's
[careful] use. [=

Seriously: this probably won't be how it's implemented, but after
having the power this last month or so... I want it.

Here's what seems to be working for me (patch format):
http://coldfusion.pastebin.com/m43115e4e

Not much there, which I like.

It's working for me, but may be horrendously flawed, and perhaps make
your hard-drive play jingle-bells, so, ya know. just say'n. =]

I'm down to try to URLize it and add something to the eclipse plugin
UI, if it's wanted (and this stuff doesn't look too ugly-- suggestions
welcome!).

:Denny
--
In order for the light to shine so brightly, the darkness must be present.
Francis Bacon

Reply all
Reply to author
Forward
0 new messages