用atoum模拟一系列方法

Mocking a series of methods with atoum

我正在尝试使用 Atoum 设计一个数据库 ($db) 模拟,它会 return 不同的值,具体取决于先前的方法调用(和参数)。

我正在使用 PHP 5.6 和 Atoum 3.2

这是我尝试过的:

$this->calling($db)->select = function($table, array $bind, $boolOperator = "AND") use ($permissionClientMapper, $db, $permissionsClientRaw){
    if($table === $permissionClientMapper->getTableName()){
        $this->calling($db)->fetchAll = function() use ($bind, $permissionsClientRaw){
            if(array_key_exists('type_service', $bind) && array_key_exists('id_service', $bind) && $bind['type_service'] === 'mutu' && $bind['id_service'] === 4012){
                return EXPECTED_RETURN_VALUE;
            }
            return null;
        };
    }
};

我会在调用(带参数)时将 return 和 EXECTED_RETURN_VALUE 的代码除外:

1/ $db->select() -> This method is called as expected
2/ $db->fetchAll() -> This one is never called

我没有在 Atoum 文档中找到这方面的任何示例。

有人可以确认这是模拟连续方法调用的正确方法吗?

我也试过在闭包中使用对数据库的引用

$this->calling($db)->select = function($table, array $bind, $boolOperator = "AND") use ($permissionClientMapper, &$db, $permissionsClientRaw){
    if($table === $permissionClientMapper->getTableName()){
        $this->calling($db)->fetchAll = function() use ($bind, $permissionsClientRaw){
            if(array_key_exists('type_service', $bind) && array_key_exists('id_service', $bind) && $bind['type_service'] === 'mutu' && $bind['id_service'] === 4012){
                return EXPECTED_RETURN_VALUE;
            }
            return null;
        };
    }
};

但这也不行。

编辑:一种解决方法可能是使用 atoum 调用顺序为每个调用 return 不同的值,然后测试模拟以检查它是用正确的参数调用的。

我会给你一些关于你的问题的见解,希望能给你一些线索来找到解决问题的方法。

因此,要验证未调用模拟方法,您可以使用 'call' 和 'never'

$this->mock($mock)->call('fetchAll')->never();

被称为:

$this->mock($mock)->call('select')->once();

为了处理你的模拟回答,你可以使用几个东西,像这样

$this->calling($db)->fetchAll[0] = null; // default answer
$this->calling($db)->fetchAll[1] = function () {....} // first call to method

如果你想要类似链的东西:当使用模拟方法 select 并在其中调用 fetchAll 方法时,答案是...... atoum 还没有提供这种行为。最好的方法是创建一个 issue 公开您的案例。

当您使用 'calling' 时,您定义了模拟的行为。只有在调用方法时,atoum 才会抓取所有内容并解析它。

所以对我来说,如果我理解正确你的问题,我会这样写:

$this->calling($db)->fetchAll = function() use ($bind){
            if(array_key_exists('type_service', $bind) && array_key_exists('id_service', $bind) && $bind['type_service'] === 'mutu' && $bind['id_service'] === 4012){
                return EXPECTED_RETURN_VALUE;
            }
            return null;
        };
$this->calling($db)->select = function($table, array $bind, $boolOperator = "AND") use ($permissionClientMapper, $db){
    if($table === $permissionClientMapper->getTableName()){
        return $db->fetchAll();
    }
};
// this is the same as your code. But It a bit more readable

$this->newTestedInstance;
$this->testedInstance->setDb($db);
$this->variable($this->testedInstance->doTheCallThatReturnNull())
    ->isEqualTo(null);
// do some change in the vars to be in the value
$this->variable($this->testedInstance->doTheCallThatReturnValue())
    ->isEqualTo(EXPECTED_RETURN_VALUE);

ps :为了帮助你走得更远,你可以阅读 http://docs.atoum.org/en/latest/asserters.html#mock and http://docs.atoum.org/en/latest/mocking_systems.html 你也可以用 'atoum'.

标记问题