PHP Developers Network

A community of PHP developers offering assistance, advice, discussion, and friendship.
 
Loading
It is currently Sun Jul 12, 2020 9:00 pm

All times are UTC - 5 hours




Post new topic Reply to topic  [ 18 posts ]  Go to page 1, 2  Next
Author Message
PostPosted: Thu Feb 04, 2010 4:14 am 
Offline
DevNet Master

Joined: Wed Feb 11, 2004 4:23 pm
Posts: 4872
Location: Palm beach, Florida
When doing TDD how do you handle hard to test features?

E.g. lazy loading, or testing AJAX vs offline "loading" strategies?

Often the test scenarios are awkward, like deleting and inserting a fake record, and querying to make sure its not found. Although this does and can be encapsulated behind a high level API I'd be interested to see if there are any other "styles" for this type of problem. I guess the central theme here is we are loading something with different strategies (ajax vs offline, lazy vs aggressive, etc..)


Top
 Profile  
 
PostPosted: Fri Feb 05, 2010 7:27 am 
Offline
DevNet Master
User avatar

Joined: Mon Sep 19, 2005 6:24 am
Posts: 3587
Location: London
Have you got any examples?

Usually it's just a case of abstracting your API to an extent that has seams, that you can inject mocks/stubs into.

Tests should not use the DB. That's one hard and fast rule I stick to.


Top
 Profile  
 
PostPosted: Sat Feb 06, 2010 4:22 am 
Offline
DevNet Master

Joined: Wed Feb 11, 2004 4:23 pm
Posts: 4872
Location: Palm beach, Florida


Top
 Profile  
 
PostPosted: Sun Feb 07, 2010 7:19 pm 
Offline
DevNet Master
User avatar

Joined: Mon Sep 19, 2005 6:24 am
Posts: 3587
Location: London
Some "test code in production" is not a bad thing. Simply put, if it is making test maintenance/coverage difficult, then it's just making code maintenance difficult.

The most common "test code in production" snippet would be:

Syntax: [ Download ] [ Hide ]
class Foo
{
  pulbic $delegate;
  public function getDelegate()
  {
    if (isset(!$this->delegate)) $this->delegate = new Delegate();
 
    return $this->_delegate;
  }
}


Nothing wrong with that. In production, you'll not even notice the difference. In testing, it's given you a seam to inject your mock/stub.

As far as DB goes.. even with regression testing, I'm not happy having it actually touch the database. The *only* time I am satisfied is with end-to-end tests, which are of course on a sandbox DB which is destroyed after test, and (re)generated at test start.

Wrap all the DB functions in a class, if you aren't using PDO or the like already, with simple methods like:
Syntax: [ Download ] [ Hide ]
class MySQL
{
  public function mysql_query($query, $resource = null)
  {
    return mysql_query($query, $resource);
  }
}


Then instead of calling functions directly, you've got a nice seam to use instead (possibly in conjunction with the above..)
Syntax: [ Download ] [ Hide ]
class Foo
{
  public $db;
 
  public function __construct()
  {
    $this->db = new MySQL();
  }
 
  public function doFoo()
  {
    $this->db->mysql_query("SELECT 'bar' FROM `baz`");
  }
//etc..
}


Then all your test has to do is mock MySQL and inject it before you call upon functionality.


Top
 Profile  
 
PostPosted: Sun Feb 07, 2010 7:49 pm 
Offline
DevNet Master
User avatar

Joined: Fri Jan 18, 2008 1:36 am
Posts: 3549
Location: Israel, ME
How do you test methods that invoke complex queries without exercising an actual database? most of the purpose of the test is to check the query is returning correct results, how can you test that with a mock?


Top
 Profile  
 
PostPosted: Sun Feb 07, 2010 10:07 pm 
Offline
DevNet Master

Joined: Wed Feb 11, 2004 4:23 pm
Posts: 4872
Location: Palm beach, Florida


Top
 Profile  
 
PostPosted: Mon Feb 08, 2010 7:29 am 
Offline
DevNet Master
User avatar

Joined: Mon Sep 19, 2005 6:24 am
Posts: 3587
Location: London


Top
 Profile  
 
PostPosted: Mon Feb 08, 2010 10:57 am 
Offline
DevNet Master
User avatar

Joined: Fri Jan 18, 2008 1:36 am
Posts: 3549
Location: Israel, ME


Top
 Profile  
 
PostPosted: Mon Feb 08, 2010 11:58 am 
Offline
DevNet Master
User avatar

Joined: Mon Sep 19, 2005 6:24 am
Posts: 3587
Location: London
Because it is not your responsibility to test that the SQL engine parses queries. :)

If you provide XML to a 3rd party XML parser, do you test that it parses XML correctly, or do you just test your app based on the parse results? :)


Top
 Profile  
 
PostPosted: Mon Feb 08, 2010 12:34 pm 
Offline
DevNet Master
User avatar

Joined: Fri Jan 18, 2008 1:36 am
Posts: 3549
Location: Israel, ME
Following on your metaphor (which is exactly the same), how do you know you are generating a valid XML? I'm not worried about how the 3rd party service will parse it, I'm just concerned that my XML isn't breaking anywhere. Back to the SQL world - it can get much more complex than generating XML, when you start using aggregate functions, grouping, subqueries and the like. Even a small typo would result in an exception thrown. How can you test that changes to the query don't break anything?


Top
 Profile  
 
PostPosted: Mon Feb 08, 2010 2:22 pm 
Offline
DevNet Master

Joined: Wed Feb 11, 2004 4:23 pm
Posts: 4872
Location: Palm beach, Florida
I'm with pytrin. If you simply assert on the SQL that gets generated you aren't effectively testing anything at all. That would be like testing your PHP code by regexing against it directly.

Personally my rule of thumb is that I follow Data Mapper, not Active Record. Tests for my Models *never* touch a db, but I do test my mappers. So my business logic can be tested without the database present. But I also get good regression testing of the database & the database layer of my app.

In the XML example actually yeah I would want to include the 3rd party system in the harness, at least in a functional test. If that system changes, my app breaks.. therefore I want to know if that happens.


Top
 Profile  
 
PostPosted: Wed Feb 10, 2010 7:55 am 
Offline
DevNet Master
User avatar

Joined: Mon Sep 19, 2005 6:24 am
Posts: 3587
Location: London
You'll know it (3rd party tool) is broken when using it.. what is this fear of run-time errors all about? :?

If you load up every tool you use into your test harness/environment, just to test your own apps code, you'll be testing the world soon. What next? Test that Apache handles HTTP transactions reliably? Test that the voltage from your electrical supply is stable? :?

You'll know that the query you are testing against is valid, because you'd have used a query tool (like MySQL Administrator) to help create it yourself first.. there is *no* feasible reason to use a real DB in a test case. It's too slow, it's too complicated (having to set/reset test data) and even transactions cannot be the answer (i.e. what happens when you need to test that your domain can rollback successfully?) plus the overhead of using a transaction.

The art of BDD/TDD is rapid development, with test coverage, not intrinsically test every nook and cranny of every single part of your app, be it your own code, or 3rd party.

There is also the explicit rule of responsibility. If you wrote it, it should be tested. If you didn't, don't test it.


Last edited by Jenk on Wed Feb 10, 2010 8:07 am, edited 1 time in total.

Top
 Profile  
 
PostPosted: Wed Feb 10, 2010 8:03 am 
Offline
DevNet Master
User avatar

Joined: Fri Jan 18, 2008 1:36 am
Posts: 3549
Location: Israel, ME
I really don't understand what you are talking about. Fear of the application breaking at run-time and the risk of regression between changes to source code is exactly what tests are meant to mitigate. Failing queries account for a significant portion of application bugs in any database-reliant application, and not because of database bugs.

The database engine doesn't change between revisions of my code. I'm testing the queries I generate, not the database parsing of it (which I assume is pretty stable). It's pretty rare to stumble upon a database bug for a stable build. The only way to test those queries is to run them through a query parser, ie. a database. I wrote the queries, therefor I should test them as per your logic - and not once on creation as you suggest. I could do that for every other piece of my code, and then I'll be missing on all the advantages of unit testing.


Top
 Profile  
 
PostPosted: Wed Feb 10, 2010 8:10 am 
Offline
DevNet Master
User avatar

Joined: Mon Sep 19, 2005 6:24 am
Posts: 3587
Location: London


Top
 Profile  
 
PostPosted: Wed Feb 10, 2010 8:21 am 
Offline
DevNet Master
User avatar

Joined: Fri Jan 18, 2008 1:36 am
Posts: 3549
Location: Israel, ME
This is a very simple static example that you can reasonably claim does not deserve a unit-test (though I don't see the harm in it). However, there are much more complicated use-cases in which it becomes very hard (and tiresome) to test manually all the scenarios for a dynamically generated complicated query. You'd also want to test it with different data (edge-cases) to make sure it doesn't break. All of this can be handled much more easily with unit-tests as opposed to manual testing (which is true for most forms of testing).


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 18 posts ]  Go to page 1, 2  Next

All times are UTC - 5 hours


Who is online

Users browsing this forum: No registered users and 5 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Jump to:  
Powered by phpBB® Forum Software © phpBB Group