4

我有一个有趣的问题,已经搜索了互联网,但还没有找到答案。

我在一家不允许员工使用 OOP 的公司工作,这有点荒谬,但工作经验很有价值。

考虑以下函数:

function get_setting_values_from_file( $parameter )
{
    exec("/usr/var/binary --options $parameter", $output, $return);
    $settings = file( $output[0] );
    foreach( $settings as $setting ) {
        if( strstr( $setting, "color") ) {
            $setting = explode( ":", $setting );
            return $setting[1];
        }
    }
    return false;
}

我需要对类似的功能进行单元测试。我目前正在使用 phpUnit 进行测试,并使用 vfsStream 库来模拟文件系统,但是exec("/usr/var/binary --options $parameter", $output, $return)当我在无法访问实际系统的情况下进行开发时,你如何模拟调用呢?处理这样的测试用例的推荐方法是什么?

感谢所有反馈。

4

2 回答 2

6

您可以exec()使用函数模拟库进行模拟。我为您制作了一个 ( php-mock),它要求您使用命名空间

namespace foo;

use phpmock\phpunit\PHPMock;

class ExecTest extends \PHPUnit_Framework_TestCase
{

    use PHPMock;

    public function testExec()
    {
        $mock = $this->getFunctionMock(__NAMESPACE__, "exec");
        $mock->expects($this->once())->willReturnCallback(
            function ($command, &$output, &$return_var) {
                $this->assertEquals("foo", $command);
                $output = "failure";
                $return_var = 1;
            }
        );

        exec("foo", $output, $return_var);
        $this->assertEquals("failure", $output);
        $this->assertEquals(1, $return_var);
    }
}
于 2015-03-30T23:08:52.973 回答
3

简单地模拟这个函数来返回你试图进入 $settings 的文本。您不需要调用可执行文件,只需创建文件或返回即可。

例如,假设函数 get_setting_values_from_file() 将设置作为数组返回,您可以简单地在测试中模拟该函数以将设置作为数组返回。创建一个测试存根来模拟包含 get_setting_values_from_file() 方法的对象,并让该模拟简单地返回与测试假设相同的 FALSE、1 或 2。

$stub = $this->getMock('GetSettingsClass');
    $stub->expects($this->any())
         ->method('get_settings_from_file')
         ->will($this->returnValue(0));

这是来自 PHPUnit 手册 - > http://phpunit.de/manual/3.8/en/test-doubles.html#test-doubles.stubs

或者,您甚至可以绕过调用,并通过创建数组并将其传递给这些函数来简单地测试在返回上工作的函数/代码。主代码中的假设示例:

...
$settings = get_setting_values_from_file( 'UserType' );
$UserType = get_user_type($settings);
return $UserType;

function get_user_type($settings)
{
    if($settings !== FALSE)         // Returned from your function if parameter is not found
    {
        switch($settings)
        {
            case 1:
                return 'User';      // Best to use Constants, but for example here only
                break;
            case 2:
                return 'Admin';
                break;
            ...
         }
    }
    else
    {
        return FALSE;
    }
}

现在,在您的测试中,您可以简单地

$this->assertFalse(get_user_type(FALSE, 'Ensure not found data is handled properly as FALSE is returned');
$this->assertEqual('User', get_user_type(1), 'Test UserType=1');
$this->assertEqual('Admin', get_user_type(1), 'Test UserType=2');
...

这些工作是因为代码不会调用必须模拟从操作系统读取的函数,而是通过调用处理设置返回值的函数来处理所有预期的返回。在这里,您只是假设从函数“get_setting_values_from_file()”返回,而不需要文件或任何模拟。

然而,这不会测试从文件中读取,我会在另一个测试中使用 setUp 和 tearDown 来实际创建一个具有您想要的值的文件(fopen/fwrite),然后调用您的函数并确保它返回预期的内容.

我希望这有助于解释我的想法。

于 2013-06-27T13:38:40.547 回答