0

I'm using an ORM and the way I get an object of the record is using FooModel::find(1). FooModel has a method I need to mock for testing. How can I do it? (Can't use the PHPUnit mock because that would give me a mocked FooModel that'll not correspond to the record with ID 1.)

Edit

Example:

class FooModel
{
    // ORM model that fetches record from the DB

    public function thisNeedsToBeMocked()
    {
        // some code here that depends on external factors so should be part of unit tests
    }
}

The way I get the record with ID 1 is:

$fooObject = FooModel::find(1);

I need to be able of mock the thisNeedsToBeMocked() of $fooObject that I have after I run the static method find().

gen_Eric
  • 223,194
  • 41
  • 299
  • 337
Jungle Hunter
  • 7,233
  • 11
  • 42
  • 67
  • Can you try to explain your question more? I'm a bit confused. – Brad Mar 23 '12 at 20:24
  • @Brad: I'll edit it. I feared it was too short. – Jungle Hunter Mar 23 '12 at 20:25
  • possible duplicate of [PHPUnit Mock Objects and Static Methods](http://stackoverflow.com/questions/2357001/phpunit-mock-objects-and-static-methods) – webbiedave Mar 23 '12 at 20:28
  • @Brad: Added more detail. Maybe that helps? – Jungle Hunter Mar 23 '12 at 20:31
  • @webbiedave: If you read both question I don't it's a possible duplicate. OP of the other question wants to mock a `static` method. I want to mock a different/separate/unrelated method of an object that's created using a `static` method. – Jungle Hunter Mar 23 '12 at 20:34
  • The question was heavily edited to add more info *after* I left the comment. Unfortunately, there's no way to remove a close vote. – webbiedave Mar 23 '12 at 20:39
  • @webbiedave: I re-read by pre-edit part and I would admit that I wasn't very clear in what I was asking. Maybe you felt it was a duplicate, I wouldn't have an idea what was being asked in that version. No worries. :) – Jungle Hunter Mar 23 '12 at 20:49

1 Answers1

0

You have hit on a classic unit testing problem. The class name you are using to call statically is part of the global namespace. That means there is no point in which you can insert a mock. This is no magic you can do here, to solve this problem you will have to make some code changes.

There many ways to solve this and there are many fors and against each of them. I will give you a simple hacker solution. If you would like something different let me know and I will code up an example.

I will also assume that you can't change the ORM from being static class based.

Here is the hacker approach, which is a very bad way of doing things, so you know. Have a variable in your class that is the class name of the ORM class you need to use. This is PHP 5.3 code.

Like so:

<?php

class Bar {
    public static $ormName = 'FooModel';

    public static function doStuff()
    {
        $className = self::$ormName;
        echo $className::find(1), "\n";
    }
}

Then in your PHPUnit test create a mock. Get it's class name, set that class name on your test subject. Now your test subject will call your mock.

There are so many ways to some this problem but some how you need a way to not use the class name directly.

SamHennessy
  • 4,288
  • 2
  • 18
  • 17
  • Thanks! I guess if it's a classic problem there's not good answer to it other than figuring out if something can be changed? – Jungle Hunter Mar 23 '12 at 21:20
  • 1
    Another option is to use the runkit PECL extension and in your bootstrap code do runkit_method_redefine('FooModel', 'find', 'return "bar"'); – bismark Mar 23 '12 at 21:26