如何为静态方法编写PHP单元测试

时间:2019-01-18 14:40:38

标签: phpunit

我对PHP单元测试非常陌生。我正在尝试为以下功能创建单元测试:

    $context = $args[0];

    if (Subscriber::instance()->isSubscriber()) {
        $context['body_class'] .= ' ' . $this->bodyClass;
    }

    return $context;

这很简单,如果User是订户,它将在数组中添加类名。订阅者是具有静态实例方法的类,该方法返回true或false。

到目前为止,我已经写了这篇文章,但我认为这是不正确的:

$subscriber = $this->getMockBuilder(Subscriber::class)
    ->disableOriginalConstructor()
    ->setMethods(['isSubscriber'])
    ->getMock();

$subscriber->expects($this->once())
    ->method('isSubscriber')
    ->will($this->returnValue(true));

$this->assertInternalType('bool',$subscriber->isSubscriber());

任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:1)

您可以测试(声明)静态方法,但不能在PHPunit中对其进行模拟或存根。

来自documentation

  

请注意,final,private和static方法不能存根   或嘲笑。 PHPUnit的测试双重功能会忽略它们,并且   保留其原始行为,除了静态方法   替换为抛出   \PHPUnit\Framework\MockObject\BadMethodCallException exception

答案 1 :(得分:1)

这是一个老问题的迟到答案,但我认为它对某人有用。

是的,您可以将 PhpUnitMockery 一起使用来模拟 PHP 静态方法!

案例:要测试的类 Foo (Foo.php) 使用了类 mockMe 的静态方法 ToBeMocked

<?php

namespace Test;

use  Test\ToBeMocked;

class Foo {

    public static function bar(){
        return 1  + ToBeMocked::mockMe();        
    }
}

ToBeMocked 类 (ToBeMocked.php)

<?php

namespace Test;

class ToBeMocked {

    public static function mockMe(){
        return 2;                
    }
}

带有模拟静态方法的 PhpUnit 测试文件 (FooTest.php)(使用 Mockery):

<?php

namespace Test;

use Mockery;
use Mockery\Adapter\Phpunit\MockeryTestCase;

// IMPORTANT: extends MockeryTestCase, NOT EXTENDS TestCase
final class FooTest extends MockeryTestCase 
{
    protected $preserveGlobalState = FALSE; // Only use local info
    protected $runTestInSeparateProcess = TRUE; // Run isolated

    /**
     * Test without mock: returns 3
     */
    public function testDefault() 
    {

        $expected = 3;
        $this->assertEquals(
            $expected,
            Foo::bar()
        );
    }

     /**
     * Test with mock: returns 6
     */
    public function testWithMock()
    {
        // Creating the mock for a static method
        Mockery::mock(
        // don't forget to prefix it with "overload:"
        'overload:Geko\MVC\Models\Test\ToBeMocked',
        // Method name and the value that it will be return
        ['mockMe' => 5]
    );
        $expected = 6;
        $this->assertEquals(
            $expected,
            Foo::bar()
        );
    }
}

运行此测试:

$ ./vendor/phpunit/phpunit/phpunit -c testes/phpunit.xml --filter FooTest
PHPUnit 9.5.4 by Sebastian Bergmann and contributors.

Runtime:       PHP 8.0.3
Configuration: testes/phpunit.xml

..                                                                  2 / 2 (100%)

Time: 00:00.068, Memory: 10.00 MB

OK (2 tests, 3 assertions)

祝你好运!