SitePoint Sponsor

User Tag List

Results 1 to 8 of 8
  1. #1
    SitePoint Guru
    Join Date
    Nov 2004
    Location
    Plano
    Posts
    643
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)

    Best way to test classes?

    Hi, I just went through and wrote all the code for my classes, and now I want to go back and test each class individually to make sure they all work...only problem is most of my classes depend on other classes to work fully so it's hard to test just one class without testing all the others at once and getting distracted.

    for example:

    Database class depends on SQLQuery, Exception, Log
    Template class depends on Validate, Database, Log
    Validate class depends on Exception
    ...etc...

    Really the only one that doesn't depend on any other classes is the Log class, which logs errors and warnings, etc...but I need to test my other classes, too.

    So I'm just curious what are some clever ways of testing one class fully without worrying about other classes messing up my results.

    Thanks!

  2. #2
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    In which way do they depend? If your dependencies are passed in from the outside, you can create mocks during the testing, and pass these in instead of the actual dependencies.

  3. #3
    SitePoint Guru
    Join Date
    Nov 2004
    Location
    Plano
    Posts
    643
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    here's a few examples of how one depends on the other...

    when Database->fetch() is called, an instance of SQLQuery is created
    when SQLQuery->__construct() is called, it will throw certain exceptions which i want to test are actually being thrown.
    when exceptions are thrown, I want to make sure they are being passed to the Log correctly
    when Log is called, one of the methods of logging is "logging" an error to the screen/user...so i want to output that via the Template class

    and ya that may be more information than you need, but I'm just trying to show how...when I try to test out how each one works...it seems like it always depends on another class working. I suppose i will do kinda what you said and create mock classes that have minimal room for error.

    Sorry, this is just new to me as I'm used to just throwing it all together and hoping the end result works, I've never really tested in this fashion before and it's a bit overwhelming how to do it right.

    Thanks.

  4. #4
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by XtrEM3 View Post
    when Database->fetch() is called, an instance of SQLQuery is created
    You can stub that out by putting the creation of the dependency in a factory. The simplest solution is to use a factory method, and then extend the Database class for the test. For example:
    PHP Code:
    class Database
    {
      function 
    fetch() {
        
    $query $this->createSQLQuery();
        return 
    $query->execute();
      }
      function 
    createSQLQuery() {
        return new 
    SQLQuery();
      }
    }
    class 
    MockDatabase extends Database
    {
      function 
    createSQLQuery() {
        return new 
    MockSQLQuery();
      }

    This allows you to test Database in isolation from SQLQuery. You can then proceed to test SQLQuery on its own.

    Testing that the constructor throws, can be done this way:
    PHP Code:
    function test_sqlquery_constructor_throws() {
      try {
        new 
    SQLQuery("some-bogus-data-that-makes-it-throw");
        
    $this->fail("Expected SQLQueryException wasn't thrown");
      } catch (
    SQLQueryException $ex) {
        
    $this->pass("Expected SQLQueryException caught");
      }

    I'm not entirely sure how you Log class is wired up with the rest of your application, so I can't advise on that.

  5. #5
    SitePoint Guru
    Join Date
    Nov 2004
    Location
    Plano
    Posts
    643
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    o wow...perfect, it's like you knew exactly how i wrote my classes. I will try out those test cases, and work from there, thanks a bunch!

  6. #6
    SitePoint Zealot
    Join Date
    Aug 2006
    Location
    Poland
    Posts
    108
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken View Post
    In which way do they depend? If your dependencies are passed in from the outside, you can create mocks during the testing, and pass these in instead of the actual dependencies.
    Do you think that not using mocks at all is a no no? I'm not using them anywhere, but as I'm rather new to unit testing (just a few months exp.), I'm thinking about my test suites design.

    I'm just using all my classes as the app would do. I write tests for low level classes first and then the high ones that depend on them. After I'm done, I always run the 'all tests' suite before commiting the changes, which takes around 30 second for now (something like 700 tests)

    Thanks

  7. #7
    SitePoint Wizard silver trophy kyberfabrikken's Avatar
    Join Date
    Jun 2004
    Location
    Copenhagen, Denmark
    Posts
    6,157
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by dan7 View Post
    Do you think that not using mocks at all is a no no? I'm not using them anywhere
    I wouldn't say that mocks are a goal in themselves. They are a useful tool for isolating one object within a composite structure (The SqlQuery+Database above is a good example). They are also important, to remove parts of your code which communicates with external services, during testing.

  8. #8
    SitePoint Guru dagfinn's Avatar
    Join Date
    Jan 2004
    Location
    Oslo, Norway
    Posts
    894
    Mentioned
    0 Post(s)
    Tagged
    0 Thread(s)
    Quote Originally Posted by kyberfabrikken View Post
    I wouldn't say that mocks are a goal in themselves. They are a useful tool for isolating one object within a composite structure (The SqlQuery+Database above is a good example). They are also important, to remove parts of your code which communicates with external services, during testing.
    What I've found is that test setups get too complex and unmanagable if too many classes are involved in the test. Mostly I prefer to mock all classes except 1) the one under test and 2) the ones that are so simple to set up that replacing it with a mock doesn't make it appreciably simpler.
    Dagfinn Reiersøl
    PHP in Action / Blog / Twitter
    "Making the impossible possible, the possible easy,
    and the easy elegant"
    -- Moshe Feldenkrais


Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •