Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Presentation done

  • Loading branch information...
commit 7776e327c410016c57b812007f5f2843f7d791c0 1 parent d0faab4
Chad Granum authored
Showing with 255 additions and 93 deletions.
  1. +255 −0 lib/Mock/Quick/Presentation.pod
  2. +0 −93 lib/Mock/Quick/Tutorial.pod
255 lib/Mock/Quick/Presentation.pod
View
@@ -0,0 +1,255 @@
+=pod
+
+=head1 NAME
+
+Mock::Quick::Presentation - Presentation of Mock::Quick to PDX.pm
+
+=head1 DESCRIPTION
+
+This is a presentation for Mock::Quick. This presentation was written for the
+portland perl mongers for the meeting on 04/13/2011.
+
+=head1 QUICK OBJECTS
+
+=over 4
+
+=item Quick objects were concieved as an api stand-in
+
+=item Emulates objects that provid fairly static information
+
+=item Useful when the information in the object is not relivant to the test
+
+=back
+
+An example function to test:
+
+ sub add_and_append {
+ my ( $numA, $numB, $subsystem ) = @_;
+ my $sum = $numA + $numB;
+
+ return $subsystem->system_name . ":" . $sum;
+ }
+
+=over 4
+
+=item We only want to test the addition, and the appending
+
+=item We do not really care what subsystem->system_name returns (tested elsware)
+
+=item Subsystem->new() needs 20 arguments, all are used to by system_name()
+
+=back
+
+Thats where quick objects come in:
+
+ is(
+ add_and_append( 2, 3, qobj( system_name => 'foo' )),
+ "foo:5",
+ "add_and_append works"
+ );
+
+=head2 METHOD AUTOVIVIFYING
+
+Sometimes you need to pass in an object that has more methods than you care to
+mock out, they only need to be present and return something.
+
+Thats where the next feature of Quick Objects comes in. Quick objects
+will autovivify methods as they are needed. The new methods will be read/write
+accessors.
+
+ my $obj = qobj();
+ $obj->foo( 'bar' );
+ is( $obj->foo, 'bar', "foo attribute was set" );
+ is(
+ $obj->foo( 'baz' ),
+ 'baz',
+ "remembers and returns whatever argument you give it."
+ );
+
+=head2 STRICT OBJECTS
+
+=over 4
+
+=item Autovivifying can be bad
+
+=item Autovivification has been reported as a bug in hashes
+
+For cases where you do not want autovivifying you can use strict objects. A
+strict object will not autovivify.
+
+ my $obj = qstrict( foo => 'foo' );
+ is( $obj->foo, 'foo' );
+ dies_ok { $obj->bar } "no bar() method defined";
+
+=back
+
+=head3 But what if you want to change the specification later?
+
+Easy!
+
+in list context C<qobj> and C<qstrict> return both the new object, and a
+control object that provides a manipulation interface.
+
+ my ( $obj, $control ) = qstrict( foo => 'foo' );
+ $control->set_attributes( bar => 'bar' );
+
+=head3 Why not just provide a manipulation interface as a method on the object?
+
+because it might conflict with the api you are attempting to mock.
+
+=head2 CUSTOM METHODS
+
+More often than not you need to mock out methods more complicated than
+accessors. You can add them to your quick object in 2 ways.
+
+You can't just assign a coderef to an accessor, that would just result in an
+accessor that returns a coderef. This is important because there are cases
+where that is what you really want.
+
+The original way to create a custom method is the C<qmeth()> function.
+
+ $obj->new_method( qmeth {
+ my $self = shift;
+ ...
+ return 'whatever';
+ });
+
+This will add a method that will be run next time you call
+C<$obj-E<gt>new_method>.
+
+Arguments will not be used to replace the method on the object like they would
+a in a get/set accessor.
+
+Some people have expressed displeasure with this API. C<qmeth {...}> seems too
+magical. The alternative is to use the control object.
+
+ my ( $obj, $control ) = qobj(...);
+ $control->set_methods( foo => sub { ... });
+
+=head2 CLEARING METHODS/ATTRIBUTES
+
+We have so far seen many ways to add methods, attributes and accessors to a
+quick object. But you can also clear them! This is particularly useful in
+strict objects where they will not autovivify back into existance.
+
+One again there are 2 ways to clear an attribute or method. The original way
+using the C<qclear> method, and the new way using the control object.
+
+ # Remove the foo() attribute and any associated value/method
+ $obj->foo( qclear() );
+
+ # Remove a whole list of attributes
+ $control->clear( qw/foo bar baz/ );
+
+=head2 CONTROL OBJECT
+
+The control object provides 2 additional methods.
+
+=over 4
+
+=item $control->strict( BOOL )
+
+Lets you toggle strict mode on and off for your object.
+
+=item $control->metrics
+
+Returns a hashref with all current attributes/methods as keys, the values
+associated with them are the counts of how many times that attribute has been
+called. Clearing an attribute will reset its metrics.
+
+=back
+
+=head1 MOCKING CLASSES
+
+Sometimes a quick object is not sufficient.
+
+=over 4
+
+=item The object you need to mock is instantiated inside the function you're testing
+
+=item You want to preserve the original class, but you need to override a subset of methods
+
+=item You want to replace the original class and prevent it from loading
+
+=item You want to implement a temporary but re-usable class specification
+
+=back
+
+=head2 TAKING OVER A CLASS
+
+The class is loaded, you want to change parts of it
+
+=over 4
+
+=item Take control of the class
+
+ require Some::Package;
+ my $control = qtakeover( 'Some::Package' );
+
+=item Have your way with it
+
+ $control->override(
+ foo => sub { ... }
+ bar => sub { ... }
+ );
+
+=item Restore the original method
+
+ $control->restore( 'foo' );
+
+=item The original class is completely restored when the control object is destroyed.
+
+ $control = undef;
+
+=back
+
+=head2 USURPING A CLASS
+
+The class is not loaded, you want to keep it that way, and put something in it's place.
+
+=over 4
+
+=item Create the package, %INC is updated for you to prevent the real one from loading.
+
+ my $control = qimplement Some::Package => ( ... );
+
+=back
+
+=head3 arguments
+
+=over 4
+
+=item auto-create new()
+
+ -with_new => 1,
+
+=item subclassing
+
+ -subclass => $class || [ @CLASSES ],
+
+=item quickly generate attributes (read/write)
+
+ -attributes => [qw/ foo bar baz /]
+
+=item simple return value methods
+
+ method => 'value'
+
+=item custom methods
+
+ do_it => sub { ... }
+
+=back
+
+The control object returned is identical to that from C<qtakeover()>.
+
+=head2 ANONYMOUS CLASSES
+
+An anonymous class is the same as userping a class, except instead of using a
+real package a temporary one is created.
+
+ my $control = qclass( ... )
+
+Takes all the same arguments as qimplement.
+
+=cut
93 lib/Mock/Quick/Tutorial.pod
View
@@ -1,93 +0,0 @@
-=pod
-
-=head1 NAME
-
-Mock::Quick::Tutorial - Tutorial/Presentation for Mock::Quick
-
-=head1 DESCRIPTION
-
-This is a tutorial that doubles as a presentation for Mock::Quick.
-
-=head1 SHOVE IT IN - MOCKING QUICKLY
-
-I<I don't know what it needs, but I know what it looks like, and where to put it.>
-
-=head2 qobj()
-
-=head2 If any object will do
-
-=head2 Minimal API specification
-
-=head2 Adding methods on the fly
-
-=head2 Control object
-
-=head1 ENLIGHTENMENT - MOCKING STRICTLY
-
-I<I have reached a higher understanding, I will grasp control.>
-
-=head2 Becoming strict
-
-=head2 qstrict()
-
-=head1 DOPPELGÄNGER - REPLACING A CLASS
-
-I<Looks like our duck, quacks like our duck... but it has a goatee...>
-
-=head2 qimplement() and qclass()
-
-=head2 use cases
-
-=head2 Attributes
-
-=head2 Shortcuts
-
-=head2 Inheritance
-
-=head2 Control object
-
-=head2 Scope warning, and cleaning up
-
-=head1 COUP D'ÉTAT - TAKING OVER A LOADED CLASS
-
-I<No really, you maintain control!... so long as we can tell you what to do.>
-
-=head2 qtakeover() and qclass() revisited
-
-=head2 Use cases
-
-=head2 Scope, and cleaning up
-
-=head1 TREE? BAM! - ANONYMOUS CLASS
-
-I<I swear! The tree jumped out, hit my car, and ran away!>
-
-=head2 qclass()
-
-=head2 How it is useful
-
-=head2 Scope, and cleaning up
-
-=head1 EXTERMINATE! - USAGE METRICS
-
-I<Yes I deleted it, but it's ok, it wasn't used anywhere. oh...>
-
-...
-
-=head1 ITS FULL OF STARS - INTERNALS
-
-I<I'm afraid I can't do that dave, oh wait.. yes I can.>
-
-=head2 Mock::Quick - Interface Layer
-
-=head2 Mock::Quick::Util - Make hard things possible
-
-=head2 Mock::Quick::Object - Dynamic Object
-
-=head2 Mock::Quick::Object::Control - Object Remote Control
-
-=head2 Mock::Quick::Method - Bless a method to make it distinct
-
-=head2 Mock::Quick::Class - Bend a class to your will
-
-=cut
Please sign in to comment.
Something went wrong with that request. Please try again.