Feature Request: Ability to override private variables

52 views
Skip to first unread message

Luis Majano

unread,
Aug 14, 2008, 1:41:10 PM8/14/08
to mxunit
Marc,

I think that with the same concept of overriding private methods with
public ones to test. It would be a good idea to have the ability to
expose private variables also. Why? Well, maybe I have some
dependencies that are private, (other objects) and I would like to
mock them if necessary. I currently can't do that as of now, unles I
inject my own mixin to override the variable.

maybe allowing for a way to override private members would be a good
idea, for mocking purposes.

Any thoughts?

Marc Esher

unread,
Aug 14, 2008, 1:56:48 PM8/14/08
to mxu...@googlegroups.com
so you mean something like:

<cffunction name="testSomething">
<cfset obj = createObject(".....)>
<cfset makeVariablePublic(obj,"myPrivateVariable")>
<cfset obj.myPrivateVariable = "foo">
....

</cffunction>

Is that what you have in mind?

Marc Esher

unread,
Aug 15, 2008, 8:08:15 AM8/15/08
to mxu...@googlegroups.com
actually, "makeVariablePublic" isn't what you're after, is it. it's
more like "injectVariable" or "injectProperty". basically, the same
behavior you get with injectMethod() (i.e. inserting new or
overriding existing methods inside a dependency or object under test),
but with variables. Is that it?

Luis Majano

unread,
Aug 15, 2008, 1:41:29 PM8/15/08
to mxunit
Yes sir!!

You got it. I have something working already:

<!--- mockProperty --->
<cffunction name="mockProperty" output="false" access="private"
returntype="void" hint="Mock a property">
<cfargument name="obj" type="any" required="true" hint="Object
where property you would like to mock is"/>
<cfargument name="propertyName" type="string" required="true"
hint="The name of the property to mock"/>
<cfargument name="propertyScope" type="string" required="false"
default="variables" hint="The scope where the property lives in"/>
<cfargument name="mockObject" type="any" required="true" hint="The
object to inject"/>
<cfscript>
/* mixin*/
arguments.obj.injectPropertyMixin = mixin.injectPropertyMixin;
/* send in property mixin */

arguments.obj.injectPropertyMixin(arguments.propertyName,arguments.mockObject,arguments.propertyScope);
/* Remove Mixin */
structDelete(arguments.obj,"injectPropertyMixin");
</cfscript>
</cffunction>

<!--- mixin --->
<cffunction name="injectPropertyMixin" hint="injects a property into
the passed scope" access="private" returntype="void" output="false">
<!--- *************************************************************
--->
<cfargument name="propertyName" type="string" required="true"
hint="The name of the property to inject."/>
<cfargument name="propertyValue" type="any" required="true"
hint="The value of the property to inject"/>
<cfargument name="scope" type="string" required="false"
default="variables" hint="The scope to which inject the property to."/
>
<!--- *************************************************************
--->
<cfscript>
/* Inject Property */
"#arguments.scope#.#arguments.propertyName#" =
arguments.propertyValue;
</cfscript>
</cffunction>



On Aug 15, 5:08 am, "Marc Esher" <marc.es...@gmail.com> wrote:
> actually, "makeVariablePublic" isn't what you're after, is it. it's
> more like "injectVariable" or "injectProperty". basically, the same
> behavior you get with injectMethod()  (i.e. inserting new or
> overriding existing methods inside a dependency or object under test),
> but with variables. Is that it?
>
> On Thu, Aug 14, 2008 at 1:56 PM, Marc Esher <marc.es...@gmail.com> wrote:
> > so you mean something like:
>
> > <cffunction name="testSomething">
> >   <cfset obj = createObject(".....)>
> >    <cfset makeVariablePublic(obj,"myPrivateVariable")>
> >   <cfset obj.myPrivateVariable = "foo">
> >  ....
>
> > </cffunction>
>
> > Is that what you have in mind?
>

Marc Esher

unread,
Aug 16, 2008, 8:01:33 AM8/16/08
to mxu...@googlegroups.com
Luis,
One question about this: why would you want to pass in an object
from which the object under test gets its property rather than just
set that property directly? for example, if you had an object with a
variable named "foo", and you wanted to change its value for the
purposes of a test, why not just do:

<cfset mockProperty(obj=objUnderTest,property="foo",propertyValue="myNewFooValue")>

Can you help me see the cases where this wouldn't suffice?

thanks a lot!

marc

Luis Majano

unread,
Aug 16, 2008, 10:46:25 AM8/16/08
to mxunit
Hi Marc, I think the naming is wrong but yes this is what you would
need:

obj = the object to inject
propertyName = THe name of the property
porpertyValue = THe value of the proeprty (any)
scope = What scope this property is in, e.g. this, variables,
instance, etc.

On Aug 16, 5:01 am, "Marc Esher" <marc.es...@gmail.com> wrote:
> Luis,
>   One question about this: why would you want to pass in an object
> from which the object under test gets its property rather than just
> set that property directly?  for example, if you had an object with a
> variable named "foo", and you wanted to change its value for the
> purposes of a test, why not just do:
>
> <cfset mockProperty(obj=objUnderTest,property="foo",propertyValue="myNewFooValue")>
>
> Can you help me see the cases where this wouldn't suffice?
>
> thanks a lot!
>
> marc
>

Marc Esher

unread,
Aug 17, 2008, 1:04:26 PM8/17/08
to mxu...@googlegroups.com
Luis, if you need to override instance variables (objects and
otherwise), why wouldn't you just provide a setter for it?

I'm assuming you had a use case / need for this, possibly for coldbox.
What is it that you're doing?

I'm asking because when we put this stuff in there, naturally we're
going to add it to the docs, and I want to make sure i thoroughly
understand the problem it solves so i can come up with good examples.

thanks luis.

marc

Luis Majano

unread,
Aug 18, 2008, 6:12:27 PM8/18/08
to mxunit
No prob Marc!!

The use case for this, is that setters are not available because the
object does not expose them. They are private variables just in use
for the object and the outside world has no business knowing or using
them. Therefore, their setters and getters are non-existent from the
object's public API (They are shy :) )

There lies the use case for such a way to be able to mock private
properties within an object.

Luis

On Aug 17, 10:04 am, "Marc Esher" <marc.es...@gmail.com> wrote:
> Luis, if you need to override instance variables (objects and
> otherwise), why wouldn't you just provide a setter for it?
>
> I'm assuming you had a use case / need for this, possibly for coldbox.
> What is it that you're doing?
>
> I'm asking because when we put this stuff in there, naturally we're
> going to add it to the docs, and I want to make sure i thoroughly
> understand the problem it solves so i can come up with good examples.
>
> thanks luis.
>
> marc
>

Marc Esher

unread,
Aug 18, 2008, 8:48:22 PM8/18/08
to mxu...@googlegroups.com
Interesting.

So in that case, why not do a makePublic on the setter, like so:

<cfset makePublic(objUnderTest,"mySetter")>
<cfset objUnderTest.mySetter(something)>

?

this is fun, luis!

marc

Luis Majano

unread,
Aug 19, 2008, 4:39:53 AM8/19/08
to mxunit
LOL,

other use case, the setter does not exist for private variables. Why
create a setter when nobody is setting it. They are just local
properties. I could make private setters for them, but

1) That will add code to the cfc
2) That is another inner class that cf will create unecessarily.


On another topic. I am creating a very simple mock factory for cf7,
since I cannot use onMissingMethod using brian's mock framework. I'll
send it over as soon as its tested. Only for cf7.

Luis

On Aug 18, 5:48 pm, "Marc Esher" <marc.es...@gmail.com> wrote:
> Interesting.
>
> So in that case, why not do a makePublic on the setter, like so:
>
> <cfset makePublic(objUnderTest,"mySetter")>
> <cfset objUnderTest.mySetter(something)>
>
> ?
>
> this is fun, luis!
>
> marc
>

Mike Rankin

unread,
Aug 19, 2008, 10:14:35 AM8/19/08
to mxunit
Sounds like there is your argument for making private setters. They
are necessary in order to make the code testable.

Luis Majano

unread,
Aug 19, 2008, 1:36:09 PM8/19/08
to mxunit
Mike, even though it would be the easy way out to create private
setters, I don't see why I should create private setters just for
testing and inflate my object with unnecessary methods. What happens
if my object has 10 private properties, should I create 10 private
setters just to test them? I dont' think so.

I can already mock properties with the code provided, so I have no use
case for adding unnecessary methods to an object.

The request is if this can be something that mxunit can provide out of
the box, for simple mocking of properties or even methods outside of
the testable object. I know that the latest mxunit introduced method
overriding, which is great when you want to override really easily,
but you still need to write a method that overwrites it. I know that
cfeasymock and brain's mockfactory due more than simple stuff, and
they are great and I use them for very complex testing scenarios.
However, by just providing SIMPLICITY, for simple mockups is something
to evaluate, since not all testing is hardcore and complicated. Some
tests might just need a simple property mockup or a simple method
mockup that returns a value.

Anyways, enought rant. Whether it get's done or not, It is a
suggestion that could provide entry level testers, the ability to
mock, without learning an entire new mocking framework and their
methodologies. For hardcore testers, kotek's mock framework and
cfeasy mock are indispensable and the learning curve should dictate
that this is the road that they should take as their testing skills
progress. The introduction of mocking to mxunit, could provide
benefitial to educate testers and provide a very easy solution and
open the door for other mock frameworks, when simple just doesn't cut
it anymore for their tests.

Hope I did not rant much!!

Luis

Alan Livie

unread,
Aug 19, 2008, 1:39:26 PM8/19/08
to mxu...@googlegroups.com
I agree with Luis.

I don't like the idea of adding methods just for testing purposes.

Mind you if its only simple setters that are needed then onMissingMethod() can help keep the code lean.


Alan
________________________________________
From: mxu...@googlegroups.com [mxu...@googlegroups.com] On Behalf Of Luis Majano [lma...@gmail.com]
Sent: 19 August 2008 18:36
To: mxunit
Subject: [mxunit:735] Re: Feature Request: Ability to override private variables

Sean Corfield

unread,
Aug 20, 2008, 9:59:37 PM8/20/08
to mxu...@googlegroups.com
On Tue, Aug 19, 2008 at 7:14 AM, Mike Rankin <Anody...@gmail.com> wrote:
> Sounds like there is your argument for making private setters. They
> are necessary in order to make the code testable.

A common Java technique is to create a test object that extends the
object being tested and have it expose setters to manipulate the
internal state. That way you don't need to do any hackery at all
(since "private" in CF is really protected in the Java sense).
--
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

Jamie Jackson

unread,
Aug 21, 2008, 11:53:15 AM8/21/08
to mxunit
I noticed this thread yesterday, and also noticed that more has
happened on this topic than this thread would indicate. It seems as
though private property injection is a done deal.

Thought I'd post this to tie up the thread's loose end.

More info: http://mxunit.org/doc/index.cfm?doc=injectproperty

Jamie

Marc Esher

unread,
Aug 21, 2008, 1:27:19 PM8/21/08
to mxu...@googlegroups.com
thanks Jamie. I blogged about it this morning
(http://mxunit.org/blog/2008/08/mxunit-102-now-available.html) but
forgot to respond to the list.

Almost all of the code was written a day or two after Luis first
posted his question, but I couldn't find the time to do the
documentation until this week, and we're trying to get in the habit of
only putting out new versions when the documentation is sufficient.

marc

Reply all
Reply to author
Forward
0 new messages