Page 1 of 1

Mock objects???

Posted: Sat Nov 11, 2006 1:02 am
by alex.barylski
Something that confused me (possibly still) is mock objetcs...

I was under the impression they were used for emulating objects/systems which don't exist.

For instance if you have a User class with createUser, updateUser, etc type methods...and you test each method...but each method interacts with a database...I assumed a Mock object was intended to replace or emulate a DB server...

This confused me because that would be a HELLUVA lot of work...and if the Mock object simply return TRUE then your code isn't exactly tested...because passing a SQL query which is flawed would cause the RDBMS to return false NOT true...

The it dawns on me...why wouldn't a DB server be available to a developer writting production code and *not* the developer writing tests???

So I assume my understanding of Mock objects were off??? *lol* The same environment should be made available to both test writers and system developers...

I assume a setUp and tearDown method would be responsible for creating a new DB connection, creating tables, etc...so a unit test could do it's actual magic without changing a production database...

Is this what Mock objects do? They are created to avoid possibly setting up a DB and tearing it down on every unit test invocation...instead you create the object once and leave it???

Cheers :)

Posted: Sat Nov 11, 2006 1:22 am
by John Cartwright
http://www.phpunit.de/pocket_guide/3.0/en/mock-objects.html wrote:Tests that only test one thing are more informative than tests where failure can come from many sources. How can you isolate your tests from external influences? Simply put, by replacing the expensive, messy, unreliable, slow, complicated resources with stubs that are automatically generated for the purpose of your tests. For example, you can replace what is in reality a complicated computation with a constant, at least for the purposes of a single test.
This is pretty much exactly what mock objects are. Although I don't believe having live database classes are always a bad thing when you are physically testing the database -- keeping in mind to use new data on every pass by using setting up test tables using setUp(), and destroying table after using tearDown() -- a database mock should typically be used in all other cases.

P.S. I'll get back to the Template Thread tommorow when I get time, didn't mean to take so long.

Posted: Sat Nov 11, 2006 1:52 am
by alex.barylski
Jcart wrote:
http://www.phpunit.de/pocket_guide/3.0/en/mock-objects.html wrote:Tests that only test one thing are more informative than tests where failure can come from many sources. How can you isolate your tests from external influences? Simply put, by replacing the expensive, messy, unreliable, slow, complicated resources with stubs that are automatically generated for the purpose of your tests. For example, you can replace what is in reality a complicated computation with a constant, at least for the purposes of a single test.
This is pretty much exactly what mock objects are. Although I don't believe having live database classes are always a bad thing when you are physically testing the database -- keeping in mind to use new data on every pass by using setting up test tables using setUp(), and destroying table after using tearDown() -- a database mock should typically be used in all other cases.

P.S. I'll get back to the Template Thread tommorow when I get time, didn't mean to take so long.
Why thank you thats awfully kind of you sir...giving me a heads up like that :)

ttyt :P I'm beat

Posted: Sat Nov 11, 2006 6:26 am
by Chris Corbyn
Mock objects, as supposed to stubs are more about testing an interface. You have groups of classes which should be message passing in a particular way for example. Using a mocks in place of the actual classes you can make assertions (sorry, expectations) about what arguments will be passed into a method, how many times it will be invoked, what happens if it returns a certain value etc.

Stubs are more for keeping the tests clean and cutting out all the background stuff that doesn't affect the tests. You can just set up your stubs as actors to pass values around but you don't make expectations about anything to do with them.

For example, an observer, wtih a notify() method. Now, you set up a scenario which means your observer receives a message from the observable and you can 1.) Check that method was invoked and 2.) Check that the expected argument was passed to it.

Code: Select all

interface Observer
{
    public function notify($message);
}

//You don't need it to actuall do anything since it's not supposed to be functional
class SomeObserver implements Observer
{
    public function notify($message) {}
}

class Observable
{
    protected $observers = array();
    
    public function attach(Observer $obj)
    {
        $this->observers[] = $obj;
    }
    
    protected function notifyMsg($message)
    {
        foreach ($this->observers as $obj)
            $obj->notify($message);
    }

    public function someMethod($number)
    {
        $this->notifyMsg($number * 10);
    }
}


//Test

class TestOfObservers extends UnitTestCase
{
    public function testObserverReceivesMessageTimesTen()
    {
        Mock::Generate('SomeObserver');
        $observer = new MockSomeObserver();
        $observer->expectOnce('notify', array(420));
        $observable = new Observable();
        $observable->attach($observer);
        $observable->someMethod(42);
    }
}