PHPUnit: How to test a method which calls another function declared in different file

爱⌒轻易说出口 提交于 2020-04-15 10:53:28

问题


I'm trying to test a method using PHPUnit, where it calls another function (standalone function, without class), which resides in different file which does a some pretty good calculation and returns a object.

This is my actual main code:

class CreateRecords
{
    public function createEntities($details)
    {
        if (trim($details['username']) == "") {
            $this->result = "Username is empty.";
        } else {
            $this->result = create_record($Details['username']);
        }       
        return $this->result;
    }
}

This create_record function, (standalone function, without class), which is core function, resides in separate file and it does pretty good calculations (calls lots of other methods/functions) and returns object, whether it is successful or not.

I can mock the createEntities method, but I want to mock the create_record function, which does all the computations and returns the result.

I have seen few posts which has a somewhat similar scenario,

phpunit testing method that calls other class methods which need mock

PHPUnit mock method used in another class

But I am unable to understand, how to mock standalone function which is declared in some different file.


回答1:


You can create new method that will be returning result from outside function. Then you can mock this new method

class CreateRecords
{
    public function createEntities($details)
    {
        if (trim($details['username']) == "") {
            $this->result = "Username is empty.";
        } else {
            $this->result = $this->createRecord($Details['username']);
        }       
        return $this->result;
    }

    public function createRecord($username){
    return create_record($username);
    }
}



回答2:


Namespaces in PHP5.3+ offer an excellent solution to this, which allows you to override built-in functions in your current namespace.

Longer term, refactoring the global create_record() into a class which can be injected into your CreateRecords class, and then mocked, would be a good way to go. In this instance, the global function would just be a simple wrapper to call the class until the entire application was updated.

To re-create the create_record($username) is not hard though, and useful for tests. The same technique can be used to override the global time() function as well.

Within the test-file, add a new (but local) namespace:

<?php
namespace Test\DatabaseAccess;

use DatabaseAccess\CreateRecord;
use PHPUnit\Framework\TestCase;

namespace DatabaseAccess {
    function create_record($username)
    {
        // pretend to do something
    }
}

class CreateRecordTest extends TestCase
{
     // test to check CreateRecord class
     // which should call the `create_record`, above
}

This is the same technique that the SymfonyBridge system uses to create ClockMock - which dynamically adds time(), sleep(), etc to the namespace that you are unit-testing (in this example, the namespace DatabaseAccess\CreateRecord, not the Test\ prefixed namespace). ClockMock (and DnsMock) does it with an eval() call, but since you know the namespace explicitly, you can write it into the test file itself for clarity.




回答3:


After reading the above (pretty good) answers and your comments saying that you cannot touch the tested class - CreateRecords, I can suggest another solution that is not ideal but should get the job done:

Create a new class that inherits\ extends from CreateRecords - CreateRecordsExtended.

The extended class should override only the tested function in question createEntities($details). so create a new one and copy the code from the original function.

Also, create a new function create_record(). Now, inside the new createEntitied, call your version of create_record - $this->create_record(), instead of calling the global function.

Now you can mock it! and even because this class is used only for testing, you can even just retun whatever you want from it, and do not even have to mock it now.

This class can reside either in the regular code folder, or as a neighbor of your testing class- as it is used only for testing.

Pros:

  • existing code is not modified at all.
  • you still use same exact functionality, besides the mocked function, which is what you wanted.

Cons:

  • you will be testing a different class then the one you wanted to, but it still close enough.
  • code inside function createEntities needs to be copied

Perhaps its not most ideal, but should get the job done. hope i helped.



来源:https://stackoverflow.com/questions/47436445/phpunit-how-to-test-a-method-which-calls-another-function-declared-in-different

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!