Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/277.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
';无法重新声明类';尝试模拟PHPUnit中的依赖项时出错_Php_Unit Testing_Testing_Mocking_Phpunit - Fatal编程技术网

';无法重新声明类';尝试模拟PHPUnit中的依赖项时出错

';无法重新声明类';尝试模拟PHPUnit中的依赖项时出错,php,unit-testing,testing,mocking,phpunit,Php,Unit Testing,Testing,Mocking,Phpunit,我正在现有的代码库上用PHPUnit实现单元测试。我对单元测试还比较陌生,但我知道目标是完全隔离正在测试的代码。这对于我的代码库来说很困难,因为许多类依赖于代码库中的其他类 依赖项是硬编码到类中的,因此无法使用依赖项注入。我也不想为了测试而重构现有代码。 因此,为了将每个类与其依赖项隔离开来,我创建了一个“mock”类库(不是通过使用PHPUnit的mock框架,而是通过创建一个包含存根函数的类库,这些存根函数根据特定输入返回我期望的结果) 问题是,如果在phpunit运行期间,我有一个调用mo

我正在现有的代码库上用PHPUnit实现单元测试。我对单元测试还比较陌生,但我知道目标是完全隔离正在测试的代码。这对于我的代码库来说很困难,因为许多类依赖于代码库中的其他类

依赖项是硬编码到类中的,因此无法使用依赖项注入。我也不想为了测试而重构现有代码。 因此,为了将每个类与其依赖项隔离开来,我创建了一个“mock”类库(不是通过使用PHPUnit的mock框架,而是通过创建一个包含存根函数的类库,这些存根函数根据特定输入返回我期望的结果)

问题是,如果在phpunit运行期间,我有一个调用mock类的测试,然后我尝试测试实际的类,我会得到一个致命的错误,因为PHP认为这是重新定义类。这里有一个简单的例子来说明我的意思。请注意,即使我取消设置已包含的类的所有实例并清除tearDown方法中的include路径,此操作仍然会失败。再说一次,我是单元测试新手,所以如果我用错误的方法进行测试或者遗漏了一些明显的东西,请让我知道

一个更大的问题可能是,这种方法是否会朝着隔离代码的方向发展,使用真实对象作为类的依赖项是否真的有好处

#### real A

require_once 'b.class.php';

class A {   
    private $b;

    public function __construct() {
        $this->b = new B();
    }

    public function myMethod($foo) {
        return $this->b->exampleMethod($foo);
    }
}


#### real B

class B {
    public function exampleMethod($foo) {
        return $foo . "bar";
    }
}


#### mock B

class B {
    public function exampleMethod($foo) {
        switch($foo) {
            case 'test':
                return 'testbar';
            default:
                throw new Exception('Unexpected input for stub function ' . __FUNCTION__);
        }
    }
}


#### test A

class TestA extends PHPUnit_Extensions_Database_TestCase {
    protected function setUp() 
    {
        // include mocks specific to this test
        set_include_path(get_include_path() . PATH_SEPARATOR . 'tests/A/mocks');

        // require the class we are testing
        require_once 'a.class.php';     

        $this->a = new A();
    }

    public function testMyMethod() {
        $this->assertEquals('testbar', $a->myMethod('test'));
    }
}

#### test B

class TestB extends PHPUnit_Extensions_Database_TestCase {
    protected function setUp()
    {
        // include mocks specific to this test
        set_include_path(get_include_path() . PATH_SEPARATOR . 'tests/B/mocks');

        // require the class we are testing
        // THIS FAILS WITH: 'PHP Fatal error:  Cannot redeclare class B'
        require_once 'b.class.php';

        $this->b = new AB();
    }   
}

我认为您需要在独立的进程中运行测试

要么给出执行测试的参数:“--process isolation”,要么设置
$this->processIsolation=true

如果由于某种原因(还有一些有效的原因)不能使用PHPUnit mocking API(或mockry),那么您需要自己创建mock类

模拟类应该与真实类具有相同的“类型”(因此类型暗示仍然有效),因此您应该扩展真实类:

#### mock B

class Mock_B extends B {

这同样适用于以下事实:在PHP中不能有两个同名的类:)

在声明mock时也可以使用名称空间

谢谢,这看起来正是我想要的,尽管我还没有测试过它。一位同事刚刚告诉我,您也可以通过在PHPUnit xml配置文件中将
processIsolation
设置为“true”来实现这一点。我编辑了我的答案:)