1DBD::Mock(3) User Contributed Perl Documentation DBD::Mock(3)
2
3
4
6 DBD::Mock - Mock database driver for testing
7
9 use DBI;
10
11 # connect to your as normal, using 'Mock' as your driver name
12 my $dbh = DBI->connect( 'DBI:Mock:', '', '' )
13 ⎪⎪ die "Cannot create handle: $DBI::errstr\n";
14
15 # create a statement handle as normal and execute with parameters
16 my $sth = $dbh->prepare( 'SELECT this, that FROM foo WHERE id = ?' );
17 $sth->execute( 15 );
18
19 # Now query the statement handle as to what has been done with it
20 my $mock_params = $sth->{mock_params};
21 print "Used statement: ", $sth->{mock_statement}, "\n",
22 "Bound parameters: ", join( ', ', @{ $params } ), "\n";
23
25 Testing with databases can be tricky. If you are developing a system
26 married to a single database then you can make some assumptions about
27 your environment and ask the user to provide relevant connection infor‐
28 mation. But if you need to test a framework that uses DBI, particularly
29 a framework that uses different types of persistence schemes, then it
30 may be more useful to simply verify what the framework is trying to do
31 -- ensure the right SQL is generated and that the correct parameters
32 are bound. "DBD::Mock" makes it easy to just modify your configuration
33 (presumably held outside your code) and just use it instead of
34 "DBD::Foo" (like DBD::Pg or DBD::mysql) in your framework.
35
36 There is no distinct area where using this module makes sense. (Some
37 people may successfully argue that this is a solution looking for a
38 problem...) Indeed, if you can assume your users have something like
39 DBD::AnyData or DBD::SQLite or if you do not mind creating a dependency
40 on them then it makes far more sense to use these legitimate driver
41 implementations and test your application in the real world -- at least
42 as much of the real world as you can create in your tests...
43
44 And if your database handle exists as a package variable or something
45 else easily replaced at test-time then it may make more sense to use
46 Test::MockObject to create a fully dynamic handle. There is an excel‐
47 lent article by chromatic about using Test::MockObject in this and
48 other ways, strongly recommended. (See "SEE ALSO" for a link)
49
50 How does it work?
51
52 "DBD::Mock" comprises a set of classes used by DBI to implement a data‐
53 base driver. But instead of connecting to a datasource and manipulating
54 data found there it tracks all the calls made to the database handle
55 and any created statement handles. You can then inspect them to ensure
56 what you wanted to happen actually happened. For instance, say you have
57 a configuration file with your database connection information:
58
59 [DBI]
60 dsn = DBI:Pg:dbname=myapp
61 user = foo
62 password = bar
63
64 And this file is read in at process startup and the handle stored for
65 other procedures to use:
66
67 package ObjectDirectory;
68
69 my ( $DBH );
70
71 sub run_at_startup {
72 my ( $class, $config ) = @_;
73 $config ⎪⎪= read_configuration( ... );
74 my $dsn = $config->{DBI}{dsn};
75 my $user = $config->{DBI}{user};
76 my $pass = $config->{DBI}{password};
77 $DBH = DBI->connect( $dsn, $user, $pass ) ⎪⎪ die ...;
78 }
79
80 sub get_database_handle {
81 return $DBH;
82 }
83
84 A procedure might use it like this (ignoring any error handling for the
85 moment):
86
87 package My::UserActions;
88
89 sub fetch_user {
90 my ( $class, $login ) = @_;
91 my $dbh = ObjectDirectory->get_database_handle;
92 my $sql = q{
93 SELECT login_name, first_name, last_name, creation_date, num_logins
94 FROM users
95 WHERE login_name = ?
96 };
97 my $sth = $dbh->prepare( $sql );
98 $sth->execute( $login );
99 my $row = $sth->fetchrow_arrayref;
100 return ( $row ) ? User->new( $row ) : undef;
101 }
102
103 So for the purposes of our tests we just want to ensure that:
104
105 1. The right SQL is being executed
106 2. The right parameters are bound
107
108 Assume whether the SQL actually works or not is irrelevant for this
109 test :-)
110
111 To do that our test might look like:
112
113 my $config = ObjectDirectory->read_configuration( ... );
114 $config->{DBI}{dsn} = 'DBI:Mock:';
115 ObjectDirectory->run_at_startup( $config );
116
117 my $login_name = 'foobar';
118 my $user = My::UserActions->fetch_user( $login_name );
119
120 # Get the handle from ObjectDirectory;
121 # this is the same handle used in the
122 # 'fetch_user()' procedure above
123 my $dbh = ObjectDirectory->get_database_handle();
124
125 # Ask the database handle for the history
126 # of all statements executed against it
127 my $history = $dbh->{mock_all_history};
128
129 # Now query that history record to
130 # see if our expectations match reality
131 cmp_ok(scalar(@{$history}), '==', 1, 'Correct number of statements executed' ;
132
133 my $login_st = $history->[0];
134 like($login_st->statement,
135 qr/SELECT login_name.*FROM users WHERE login_name = ?/sm,
136 'Correct statement generated' );
137
138 my $params = $login_st->bound_params;
139 cmp_ok(scalar(@{$params}), '==', 1, 'Correct number of parameters bound');
140 is($params->[0], $login_name, 'Correct value for parameter 1' );
141
142 # Reset the handle for future operations
143 $dbh->{mock_clear_history} = 1;
144
145 The list of properties and what they return is listed below. But in an
146 overall view:
147
148 · A database handle contains the history of all statements created
149 against it. Other properties set for the handle (e.g., 'PrintEr‐
150 ror', 'RaiseError') are left alone and can be queried as normal,
151 but they do not affect anything. (A future feature may track the
152 sequence/history of these assignments but if there is no demand it
153 probably will not get implemented.)
154
155 · A statement handle contains the statement it was prepared with plus
156 all bound parameters or parameters passed via "execute()". It can
157 also contain predefined results for the statement handle to
158 'fetch', track how many fetches were called and what its current
159 record is.
160
161 A Word of Warning
162
163 This may be an incredibly naive implementation of a DBD. But it works
164 for me ...
165
167 Since this is a normal DBI statement handle we need to expose our
168 tracking information as properties (accessed like a hash) rather than
169 methods.
170
171 Database Driver Properties
172
173 mock_connect_fail
174 This is a boolean property which when set to true (1) will not
175 allow DBI to connect. This can be used to simulate a DSN error or
176 authentication failure. This can then be set back to false (0) to
177 resume normal DBI operations. Here is an example of how this works:
178
179 # install the DBD::Mock driver
180 my $drh = DBI->install_driver('Mock');
181
182 $drh->{mock_connect_fail} = 1;
183
184 # this connection will fail
185 my $dbh = DBI->connect('dbi:Mock:', '', '') ⎪⎪ die "Cannot connect";
186
187 # this connection will throw an exception
188 my $dbh = DBI->connect('dbi:Mock:', '', '', { RaiseError => 1 });
189
190 $drh->{mock_connect_fail} = 0;
191
192 # this will work now ...
193 my $dbh = DBI->connect(...);
194
195 This feature is conceptually different from the 'mock_can_connect'
196 attribute of the $dbh in that it has a driver-wide scope, where
197 'mock_can_connect' is handle-wide scope. It also only prevents the
198 initial connection, any $dbh handles created prior to setting
199 'mock_connect_fail' to true (1) will still go on working just fine.
200
201 mock_data_sources
202 This is an ARRAY reference which holds fake data sources which are
203 returned by the Driver and Database Handle's "data_source()"
204 method.
205
206 mock_add_data_sources
207 This takes a string and adds it to the 'mock_data_sources'
208 attribute.
209
210 Database Handle Properties
211
212 mock_all_history
213 Returns an array reference with all history (a.k.a.
214 "DBD::Mock::StatementTrack") objects created against the database
215 handle in the order they were created. Each history object can then
216 report information about the SQL statement used to create it, the
217 bound parameters, etc..
218
219 mock_all_history_iterator
220 Returns a "DBD::Mock::StatementTrack::Iterator" object which will
221 iterate through the current set of "DBD::Mock::StatementTrack"
222 object in the history. See the DBD::Mock::StatementTrack::Iterator
223 documentation below for more information.
224
225 mock_clear_history
226 If set to a true value all previous statement history operations
227 will be erased. This includes the history of currently open han‐
228 dles, so if you do something like:
229
230 my $dbh = get_handle( ... );
231 my $sth = $dbh->prepare( ... );
232 $dbh->{mock_clear_history} = 1;
233 $sth->execute( 'Foo' );
234
235 You will have no way to learn from the database handle that the
236 statement parameter 'Foo' was bound.
237
238 This is useful mainly to ensure you can isolate the statement his‐
239 tories from each other. A typical sequence will look like:
240
241 set handle to framework
242 perform operations
243 analyze mock database handle
244 reset mock database handle history
245 perform more operations
246 analyze mock database handle
247 reset mock database handle history
248 ...
249
250 mock_can_connect
251 This statement allows you to simulate a downed database connection.
252 This is useful in testing how your application/tests will perform
253 in the face of some kind of catastrophic event such as a network
254 outage or database server failure. It is a simple boolean value
255 which defaults to on, and can be set like this:
256
257 # turn the database off
258 $dbh->{mock_can_connect} = 0;
259
260 # turn it back on again
261 $dbh->{mock_can_connect} = 1;
262
263 The statement handle checks this value as well, so something like
264 this will fail in the expected way:
265
266 $dbh = DBI->connect( 'DBI:Mock:', '', '' );
267 $dbh->{mock_can_connect} = 0;
268
269 # blows up!
270 my $sth = eval { $dbh->prepare( 'SELECT foo FROM bar' ) });
271 if ( $@ ) {
272 # Here, $DBI::errstr = 'No connection present'
273 }
274
275 Turning off the database after a statement prepare will fail on the
276 statement "execute()", which is hopefully what you would expect:
277
278 $dbh = DBI->connect( 'DBI:Mock:', '', '' );
279
280 # ok!
281 my $sth = eval { $dbh->prepare( 'SELECT foo FROM bar' ) });
282 $dbh->{mock_can_connect} = 0;
283
284 # blows up!
285 $sth->execute;
286
287 Similarly:
288
289 $dbh = DBI->connect( 'DBI:Mock:', '', '' );
290
291 # ok!
292 my $sth = eval { $dbh->prepare( 'SELECT foo FROM bar' ) });
293
294 # ok!
295 $sth->execute;
296
297 $dbh->{mock_can_connect} = 0;
298
299 # blows up!
300 my $row = $sth->fetchrow_arrayref;
301
302 Note: The handle attribute "Active" and the handle method "ping"
303 will behave according to the value of "mock_can_connect". So if
304 "mock_can_connect" were to be set to 0 (or off), then both "Active"
305 and "ping" would return false values (or 0).
306
307 mock_add_resultset( \@resultset ⎪ \%sql_and_resultset )
308 This stocks the database handle with a record set, allowing you to
309 seed data for your application to see if it works properly.. Each
310 recordset is a simple arrayref of arrays with the first arrayref
311 being the fieldnames used. Every time a statement handle is created
312 it asks the database handle if it has any resultsets available and
313 if so uses it.
314
315 Here is a sample usage, partially from the test suite:
316
317 my @user_results = (
318 [ 'login', 'first_name', 'last_name' ],
319 [ 'cwinters', 'Chris', 'Winters' ],
320 [ 'bflay', 'Bobby', 'Flay' ],
321 [ 'alincoln', 'Abe', 'Lincoln' ],
322 );
323 my @generic_results = (
324 [ 'foo', 'bar' ],
325 [ 'this_one', 'that_one' ],
326 [ 'this_two', 'that_two' ],
327 );
328
329 my $dbh = DBI->connect( 'DBI:Mock:', '', '' );
330 $dbh->{mock_add_resultset} = \@user_results; # add first resultset
331 $dbh->{mock_add_resultset} = \@generic_results; # add second resultset
332 my ( $sth );
333 eval {
334 $sth = $dbh->prepare( 'SELECT login, first_name, last_name FROM foo' );
335 $sth->execute();
336 };
337
338 # this will fetch rows from the first resultset...
339 my $row1 = $sth->fetchrow_arrayref;
340 my $user1 = User->new( login => $row->[0],
341 first => $row->[1],
342 last => $row->[2] );
343 is( $user1->full_name, 'Chris Winters' );
344
345 my $row2 = $sth->fetchrow_arrayref;
346 my $user2 = User->new( login => $row->[0],
347 first => $row->[1],
348 last => $row->[2] );
349 is( $user2->full_name, 'Bobby Flay' );
350 ...
351
352 my $sth_generic = $dbh->prepare( 'SELECT foo, bar FROM baz' );
353 $sth_generic->execute;
354
355 # this will fetch rows from the second resultset...
356 my $row = $sth->fetchrow_arrayref;
357
358 You can also associate a resultset with a particular SQL statement
359 instead of adding them in the order they will be fetched:
360
361 $dbh->{mock_add_resultset} = {
362 sql => 'SELECT foo, bar FROM baz',
363 results => [
364 [ 'foo', 'bar' ],
365 [ 'this_one', 'that_one' ],
366 [ 'this_two', 'that_two' ],
367 ],
368 };
369
370 This will return the given results when the statement 'SELECT foo,
371 bar FROM baz' is prepared. Note that they will be returned every
372 time the statement is prepared, not just the first. It should also
373 be noted that if you want, for some reason, to change the result
374 set bound to a particular SQL statement, all you need to do is add
375 the result set again with the same SQL statement and DBD::Mock will
376 overwrite it.
377
378 It should also be noted that the "rows" method will return the num‐
379 ber of records stocked in the result set. So if your code/applica‐
380 tion makes use of the "$sth->rows" method for things like UPDATE
381 and DELETE calls you should stock the result set like so:
382
383 $dbh->{mock_add_resultset} = {
384 sql => 'UPDATE foo SET baz = 1, bar = 2',
385 # this will appear to have updated 3 rows
386 results => [[ 'rows' ], [], [], []],
387 };
388
389 # or ...
390
391 $dbh->{mock_add_resultset} = {
392 sql => 'DELETE FROM foo WHERE bar = 2',
393 # this will appear to have deleted 1 row
394 results => [[ 'rows' ], []],
395 };
396
397 Now I admit this is not the most elegant way to go about this, but
398 it works for me for now, and until I can come up with a better
399 method, or someone sends me a patch ;) it will do for now.
400
401 If you want a given statement to fail, you will have to use the
402 hashref method and add a 'failure' key. That key can be handed an
403 arrayref with the error number and error string, in that order. It
404 can also be handed a hashref with two keys - errornum and
405 errorstring. If the 'failure' key has no useful value associated
406 with it, the errornum will be '1' and the errorstring will be
407 'Unknown error'.
408
409 mock_get_info
410 This attribute can be used to set up values for get_info(). It
411 takes a hashref of attribute_name/value pairs. See DBI for more
412 information on the information types and their meaning.
413
414 mock_session
415 This attribute can be used to set a current DBD::Mock::Session
416 object. For more information on this, see the DBD::Mock::Session
417 docs below. This attribute can also be used to remove the current
418 session from the $dbh simply by setting it to "undef".
419
420 mock_last_insert_id
421 This attribute is incremented each time an INSERT statement is
422 passed to "prepare" on a per-handle basis. It's starting value can
423 be set with the 'mock_start_insert_id' attribute (see below).
424
425 This attribute also can be used with an ARRAY ref parameter, it's
426 behavior is slightly different in that instead of incrementing the
427 value for every "prepare" it will only increment for each "exe‐
428 cute". This allows it to be used over multiple "execute" calls in a
429 single $sth. It's usage looks like this:
430
431 $dbh->{mock_last_insert_id} = [ 'Foo', 10 ];
432
433 my $sth = $dbh->prepare('INSERT INTO Foo (foo, bar) VALUES(?, ?)');
434
435 $sth->execute(1, 2);
436 # $dbh->{mock_last_insert_id} == 10
437
438 $sth->execute(3, 4);
439 # $dbh->{mock_last_insert_id} == 11
440
441 For more examples, please refer to the test file
442 t/025_mock_last_insert_id.t.
443
444 mock_start_insert_id
445 This attribute can be used to set a start value for the
446 'mock_last_insert_id' attribute. It can also be used to effectively
447 reset the 'mock_last_insert_id' attribute as well.
448
449 mock_add_parser
450 DBI provides some simple parsing capabilities for 'SELECT' state‐
451 ments to ensure that placeholders are bound properly. And typically
452 you may simply want to check after the fact that a statement is
453 syntactically correct, or at least what you expect.
454
455 But other times you may want to parse the statement as it is pre‐
456 pared rather than after the fact. There is a hook in this mock
457 database driver for you to provide your own parsing routine or
458 object.
459
460 The syntax is simple:
461
462 $dbh->{mock_add_parser} = sub {
463 my ( $sql ) = @_;
464 unless ( $sql =~ /some regex/ ) {
465 die "does not contain secret fieldname";
466 }
467 };
468
469 You can also add more than one for a handle. They will be called in
470 order, and the first one to fail will halt the parsing process:
471
472 $dbh->{mock_add_parser} = \&parse_update_sql;
473 $dbh->{mock_add-parser} = \&parse_insert_sql;
474
475 Depending on the 'PrintError' and 'RaiseError' settings in the
476 database handle any parsing errors encountered will issue a "warn"
477 or "die". No matter what the statement handle will be "undef".
478
479 Instead of providing a subroutine reference you can use an object.
480 The only requirement is that it implements the method "parse()" and
481 takes a SQL statement as the only argument. So you should be able
482 to do something like the following (untested):
483
484 my $parser = SQL::Parser->new( 'mysql', { RaiseError => 1 } );
485 $dbh->{mock_add_parser} = $parser;
486
487 mock_data_sources & mock_add_data_sources
488 These properties will dispatch to the Driver's properties of the
489 same name.
490
491 Database Driver Methods
492
493 last_insert_id
494 This returns the value of "mock_last_insert_id".
495
496 In order to capture begin_work(), commit(), and rollback(), DBD::Mock
497 will create statements for them, as if you had issued them in the
498 appropriate SQL command line program. They will go through the standard
499 prepare()-execute() cycle, meaning that any custom SQL parsers will be
500 triggered and DBD::Mock::Session will need to know about these state‐
501 ments.
502
503 begin_work
504 This will create a statement with SQL of "BEGIN WORK" and no param‐
505 eters.
506
507 commit
508 This will create a statement with SQL of "COMMIT" and no parame‐
509 ters.
510
511 rollback
512 This will create a statement with SQL of "ROLLBACK" and no parame‐
513 ters.
514
515 Statement Handle Properties
516
517 Active
518 Returns true if the handle is a 'SELECT' and has more records to
519 fetch, false otherwise. (From the DBI.)
520
521 mock_statement
522 The SQL statement this statement handle was "prepare"d with. So if
523 the handle were created with:
524
525 my $sth = $dbh->prepare( 'SELECT * FROM foo' );
526
527 This would return:
528
529 SELECT * FROM foo
530
531 The original statement is unmodified so if you are checking against
532 it in tests you may want to use a regex rather than a straight
533 equality check. (However if you use a phrasebook to store your SQL
534 externally you are a step ahead...)
535
536 mock_fields
537 Fields used by the statement. As said elsewhere we do no analysis
538 or parsing to find these, you need to define them beforehand. That
539 said, you do not actually need this very often.
540
541 Note that this returns the same thing as the normal statement prop‐
542 erty 'FIELD'.
543
544 mock_params
545 Returns an arrayref of parameters bound to this statement in the
546 order specified by the bind type. For instance, if you created and
547 stocked a handle with:
548
549 my $sth = $dbh->prepare( 'SELECT * FROM foo WHERE id = ? AND is_active = ?' );
550 $sth->bind_param( 2, 'yes' );
551 $sth->bind_param( 1, 7783 );
552
553 This would return:
554
555 [ 7738, 'yes' ]
556
557 The same result will occur if you pass the parameters via "exe‐
558 cute()" instead:
559
560 my $sth = $dbh->prepare( 'SELECT * FROM foo WHERE id = ? AND is_active = ?' );
561 $sth->execute( 7783, 'yes' );
562
563 mock_records
564 An arrayref of arrayrefs representing the records the mock state‐
565 ment was stocked with.
566
567 mock_num_records
568 Number of records the mock statement was stocked with; if never
569 stocked it is still 0. (Some weirdos might expect undef...)
570
571 mock_num_rows
572 This returns the same value as mock_num_records. And is what is
573 returned by the "rows" method of the statement handle.
574
575 mock_current_record_num
576 Current record the statement is on; returns 0 in the instances when
577 you have not yet called "execute()" and if you have not yet called
578 a "fetch" method after the execute.
579
580 mock_is_executed
581 Whether "execute()" has been called against the statement handle.
582 Returns 'yes' if so, 'no' if not.
583
584 mock_is_finished
585 Whether "finish()" has been called against the statement handle.
586 Returns 'yes' if so, 'no' if not.
587
588 mock_is_depleted
589 Returns 'yes' if all the records in the recordset have been
590 returned. If no "fetch()" was executed against the statement, or If
591 no return data was set this will return 'no'.
592
593 mock_my_history
594 Returns a "DBD::Mock::StatementTrack" object which tracks the
595 actions performed by this statement handle. Most of the actions are
596 separately available from the properties listed above, so you
597 should never need this.
598
600 This module can be used to emulate Apache::DBI style DBI connection
601 pooling. Just as with Apache::DBI, you must enable DBD::Mock::Pool
602 before loading DBI.
603
604 use DBD::Mock qw(Pool);
605 # followed by ...
606 use DBI;
607
608 While this may not seem to make a lot of sense in a single-process
609 testing scenario, it can be useful when testing code which assumes a
610 multi-process Apache::DBI pooled environment.
611
613 Under the hood this module does most of the work with a
614 "DBD::Mock::StatementTrack" object. This is most useful when you are
615 reviewing multiple statements at a time, otherwise you might want to
616 use the "mock_*" statement handle attributes instead.
617
618 new( %params )
619 Takes the following parameters:
620
621 * return_data: Arrayref of return data records
622
623 * fields: Arrayref of field names
624
625 * bound_params: Arrayref of bound parameters
626
627 statement (Statement attribute 'mock_statement')
628 Gets/sets the SQL statement used.
629
630 fields (Statement attribute 'mock_fields')
631 Gets/sets the fields to use for this statement.
632
633 bound_params (Statement attribute 'mock_params')
634 Gets/set the bound parameters to use for this statement.
635
636 return_data (Statement attribute 'mock_records')
637 Gets/sets the data to return when asked (that is, when someone
638 calls 'fetch' on the statement handle).
639
640 current_record_num (Statement attribute 'mock_current_record_num')
641 Gets/sets the current record number.
642
643 is_active() (Statement attribute 'Active')
644 Returns true if the statement is a SELECT and has more records to
645 fetch, false otherwise. (This is from the DBI, see the 'Active'
646 docs under 'ATTRIBUTES COMMON TO ALL HANDLES'.)
647
648 is_executed( $yes_or_no ) (Statement attribute 'mock_is_executed')
649 Sets the state of the tracker 'executed' flag.
650
651 is_finished( $yes_or_no ) (Statement attribute 'mock_is_finished')
652 If set to 'yes' tells the tracker that the statement is finished.
653 This resets the current record number to '0' and clears out the
654 array ref of returned records.
655
656 is_depleted() (Statement attribute 'mock_is_depleted')
657 Returns true if the current record number is greater than the num‐
658 ber of records set to return.
659
660 num_fields
661 Returns the number of fields set in the 'fields' parameter.
662
663 num_rows
664 Returns the number of records in the current result set.
665
666 num_params
667 Returns the number of parameters set in the 'bound_params' parame‐
668 ter.
669
670 bound_param( $param_num, $value )
671 Sets bound parameter $param_num to $value. Returns the arrayref of
672 currently-set bound parameters. This corresponds to the
673 'bind_param' statement handle call.
674
675 bound_param_trailing( @params )
676 Pushes @params onto the list of already-set bound parameters.
677
678 mark_executed()
679 Tells the tracker that the statement has been executed and resets
680 the current record number to '0'.
681
682 next_record()
683 If the statement has been depleted (all records returned) returns
684 undef; otherwise it gets the current recordfor returning, incre‐
685 ments the current record number and returns the current record.
686
687 to_string()
688 Tries to give an decent depiction of the object state for use in
689 debugging.
690
692 This object can be used to iterate through the current set of
693 "DBD::Mock::StatementTrack" objects in the history by fetching the
694 'mock_all_history_iterator' attribute from a database handle. This
695 object is very simple and is meant to be a convience to make writing
696 long test script easier. Aside from the constructor ("new") this object
697 has only one method.
698
699 next
700
701 Calling "next" will return the next "DBD::Mock::StatementTrack"
702 object in the history. If there are no more "DBD::Mock::Statement‐
703 Track" objects available, then this method will return false.
704
705 reset
706
707 This will reset the internal pointer to the begining of the state‐
708 ment history.
709
711 The DBD::Mock::Session object is an alternate means of specifying the
712 SQL statements and result sets for DBD::Mock. The idea is that you can
713 specify a complete 'session' of usage, which will be verified through
714 DBD::Mock. Here is an example:
715
716 my $session = DBD::Mock::Session->new('my_session' => (
717 {
718 statement => "SELECT foo FROM bar", # as a string
719 results => [[ 'foo' ], [ 'baz' ]]
720 },
721 {
722 statement => qr/UPDATE bar SET foo \= \'bar\'/, # as a reg-exp
723 results => [[]]
724 },
725 {
726 statement => sub { # as a CODE ref
727 my ($SQL, $state) = @_;
728 return $SQL eq "SELECT foo FROM bar";
729 },
730 results => [[ 'foo' ], [ 'bar' ]]
731 },
732 {
733 # with bound parameters
734 statement => "SELECT foo FROM bar WHERE baz = ? AND borg = ?",
735 # check exact bound param value,
736 # then check it against regexp
737 bound_params => [ 10, qr/\d+/ ],
738 results => [[ 'foo' ], [ 'baz' ]]
739 }
740 ));
741
742 As you can see, a session is essentially made up a list of HASH refer‐
743 ences we call 'states'. Each state has a 'statement' and a set of
744 'results'. If DBD::Mock finds a session in the 'mock_session'
745 attribute, then it will pass the current $dbh and SQL statement to that
746 DBD::Mock::Session. The SQL statement will be checked against the
747 'statement' field in the current state. If it passes, then the
748 'results' of the current state will get feed to DBD::Mock through the
749 'mock_add_resultset' attribute. We then advance to the next state in
750 the session, and wait for the next call through DBD::Mock. If at any
751 time the SQL statement does not match the current state's 'statement',
752 or the session runs out of available states, an error will be raised
753 (and propagated through the normal DBI error handling based on your
754 values for RaiseError and PrintError).
755
756 Also, as can be seen in the the session element, bound parameters can
757 also be supplied and tested. In this statement, the SQL is compared,
758 then when the statement is executed, the bound parameters are also
759 checked. The bound parameters much match in both number of parameters
760 and the parameters themselves, or an error will be raised.
761
762 As can also be seen in the example above, 'statement' fields can come
763 in many forms. The simplest is a string, which will be compared using
764 "eq" against the currently running statement. The next is a reg-exp
765 reference, this too will get compared against the currently running
766 statement. The last option is a CODE ref, this is sort of a catch-all
767 to allow for a wide range of SQL comparison approaches (including using
768 modules like SQL::Statement or SQL::Parser for detailed functional com‐
769 parisons). The first argument to the CODE ref will be the currently
770 active SQL statement to compare against, the second argument is a ref‐
771 erence to the current state HASH (in case you need to alter the
772 results, or store extra information). The CODE is evaluated in boolean
773 context and throws and exception if it is false.
774
775 new ($session_name, @session_states)
776
777 A $session_name can be optionally be specified, along with at least
778 one @session_states. If you don't specify a $session_name, then a
779 default one will be created for you. The @session_states must all
780 be HASH references as well, if this conditions fail, an exception
781 will be thrown.
782
783 verify_statement ($dbh, $SQL)
784
785 This will check the $SQL against the current state's 'statement'
786 value, and if it passes will add the current state's 'results' to
787 the $dbh. If for some reason the 'statement' value is bad, not of
788 the prescribed type, an exception is thrown. See above for more
789 details.
790
791 verify_bound_params ($dbh, $params)
792
793 If the 'bound_params' slot is available in the current state, this
794 will check the $params against the current state's 'bound_params'
795 value. Both number of parameters and the parameters themselves must
796 match, or an error will be raised.
797
798 reset
799
800 Calling this method will reset the state of the session object so
801 that it can be reused.
802
804 All functionality listed here is highly experimental and should be used
805 with great caution (if at all).
806
807 Error handling in mock_add_resultset
808 We have added experimental erro handling in mock_add_resultset the
809 best example is the test file t/023_statement_failure.t, but it
810 looks something like this:
811
812 $dbh->{mock_add_resultset} = {
813 sql => 'SELECT foo FROM bar',
814 results => DBD::Mock->NULL_RESULTSET,
815 failure => [ 5, 'Ooops!' ],
816 };
817
818 The 5 is the DBI error number, and 'Ooops!' is the error string
819 passed to DBI. This basically allows you to force an error condi‐
820 tion to occur when a given SQL statement is execute. We are cur‐
821 rently working on allowing more control on the 'when' and 'where'
822 the error happens, look for it in future releases.
823
824 Attribute Aliasing
825 Basically this feature allows you to alias attributes to other
826 attributes. So for instance, you can alias a commonly expected
827 attribute like 'mysql_insertid' to something DBD::Mock already has
828 like 'mock_last_insert_id'. While you can also just set
829 'mysql_insertid' yourself, this functionality allows it to take
830 advantage of things like the autoincrementing of the
831 'mock_last_insert_id' attribute.
832
833 Right now this feature is highly experimental, and has been added
834 as a first attempt to automatically handle some of the DBD specific
835 attributes which are commonly used/accessed in DBI programming. The
836 functionality is off by default so as to not cause any issues with
837 backwards compatability, but can easily be turned on and off like
838 this:
839
840 # turn it on
841 $DBD::Mock::AttributeAliasing++;
842
843 # turn it off
844 $DBD::Mock::AttributeAliasing = 0;
845
846 Once this is turned on, you will need to choose a database specific
847 attribute aliasing table like so:
848
849 DBI->connect('dbi:Mock:MySQL', '', '');
850
851 The 'MySQL' in the DSN will be picked up and the MySQL specific
852 attribute aliasing will be used.
853
854 Right now only MySQL is supported by this feature, and even that
855 support is very minimal. Currently the MySQL $dbh and $sth
856 attributes 'mysql_insertid' are aliased to the $dbh attribute
857 'mock_last_insert_id'. It is possible to add more aliases though,
858 using the "DBD::Mock:_set_mock_attribute_aliases" function (see the
859 source code for details).
860
862 Odd $dbh attribute behavior
863 When writing the test suite I encountered some odd behavior with
864 some $dbh attributes. I still need to get deeper into how DBD's
865 work to understand what it is that is actually doing wrong.
866
868 Make DBD specific handlers
869 Each DBD has its own quirks and issues, it would be nice to be able
870 to handle those issues with DBD::Mock in some way. I have an number
871 of ideas already, but little time to sit down and really flesh them
872 out. If you have any suggestions or thoughts, feel free to email me
873 with them.
874
875 Enhance the DBD::Mock::StatementTrack object
876 I would like to have the DBD::Mock::StatementTrack object handle
877 more of the mock_* attributes. This would encapsulate much of the
878 mock_* behavior in one place, which would be a good thing.
879
880 I would also like to add the ability to bind a subroutine (or pos‐
881 sibly an object) to the result set, so that the results can be
882 somewhat more dynamic and allow for a more realistic interaction.
883
885 We use Devel::Cover to test the code coverage of my tests, below is the
886 Devel::Cover report on this module test suite.
887
888 ---------------------------- ------ ------ ------ ------ ------ ------ ------
889 File stmt bran cond sub pod time total
890 ---------------------------- ------ ------ ------ ------ ------ ------ ------
891 blib/lib/DBD/Mock.pm 92.0 86.6 77.9 95.3 0.0 100.0 89.5
892 Total 92.0 86.6 77.9 95.3 0.0 100.0 89.5
893 ---------------------------- ------ ------ ------ ------ ------ ------ ------
894
896 DBI
897
898 DBD::NullP, which provided a good starting point
899
900 Test::MockObject, which provided the approach
901
902 Test::MockObject article -
903 <http://www.perl.com/pub/a/2002/07/10/tmo.html>
904
905 Perl Code Kata: Testing Databases -
906 <http://www.perl.com/pub/a/2005/02/10/database_kata.html>
907
909 We have created a DBD::Mock google group for discussion/questions about
910 this module.
911
912 <http://groups-beta.google.com/group/DBDMock>
913
915 Thanks to Ryan Gerry for his patch in RT #26604
916 Thanks to Marc Beyer for his patch in RT #16951
917 Thanks to Justin DeVuyst for the mock_connect_fail idea
918 Thanks to Thilo Planz for the code for "bind_param_inout"
919 Thanks to Shlomi Fish for help tracking down RT Bug #11515
920 Thanks to Collin Winter for the patch to fix the "begin_work()", "com‐
921 mit()" and "rollback()" methods.
922 Thanks to Andrew McHarg <amcharg@acm.org> for "fetchall_hashref()",
923 "fetchrow_hashref()" and "selectcol_arrayref()" methods and tests.
924 Thanks to Andrew W. Gibbs for the "mock_last_insert_ids" patch and test
925 Thanks to Chas Owens for patch and test for the "mock_can_prepare",
926 "mock_can_execute", and "mock_can_fetch" features.
927
929 Copyright (C) 2004 Chris Winters <chris@cwinters.com>
930
931 Copyright (C) 2004-2007 Stevan Little <stevan@iinteractive.com>
932
933 Copyright (C) 2007 Rob Kinyon <rob.kinyon@gmail.com>
934
935 This library is free software; you can redistribute it and/or modify it
936 under the same terms as Perl itself.
937
939 Chris Winters <chris@cwinters.com>
940
941 Stevan Little <stevan@iinteractive.com>
942
943 Rob Kinyon <rob.kinyon@gmail.com>
944
945
946
947perl v5.8.8 2007-10-24 DBD::Mock(3)