我试图使用PHPUnit测试一个方法,它调用另一个函数(独立函数,没有类),它驻留在不同的文件中,它做了一些非常好的计算并返回一个对象。
这是我的实际主要代码:
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;
}
}
这个create_record
函数,(独立函数,没有类),它是核心函数,驻留在单独的文件中,它做了很好的计算(调用了很多其他方法/ functions )并返回对象,无论它是否成功。
我可以模拟createEntities
方法,但我想模拟create_record
函数,它执行所有计算并返回结果。
我见过很少有类似情况的帖子,
phpunit testing method that calls other class methods which need mock
PHPUnit mock method used in another class
但我无法理解,如何模拟在某个不同文件中声明的独立函数。
答案 0 :(得分:1)
您可以创建将从外部函数返回结果的新方法。 然后你可以模拟这个新方法
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);
}
}
答案 1 :(得分:0)
PHP5.3 +中的命名空间为此提供了一个很好的解决方案,它允许您覆盖当前命名空间中的内置函数。
从长远来看,将全局create_record()
重构为一个可以注入CreateRecords
类,然后进行模拟的类将是一个很好的方法。在这个例子中,全局函数只是一个简单的包装器来调用类,直到更新整个应用程序。
重新创建create_record($username)
虽然并不难,但对测试很有用。同样的技术也可用于覆盖全局time()
函数。
在测试文件中,添加一个新的(但是本地的)命名空间:
<?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
}
这与SymfonyBridge系统用于创建ClockMock的技术相同 - 它动态地将time()
,sleep()
等添加到您进行单元测试的命名空间中(在此示例中) ,命名空间DatabaseAccess\CreateRecord
,而不是Test \ prefixed命名空间)。 ClockMock(和DnsMock)通过eval()
调用来完成它,但由于您明确知道了命名空间,因此为了清楚起见,您可以将其写入测试文件本身。
答案 2 :(得分:0)
在阅读上述(相当不错的)答案后,您的评论说您无法触及测试类 - CreateRecords
,
我可以建议另一个不理想的解决方案,但应该完成工作:
创建一个继承\ {extends CreateRecords
- CreateRecordsExtended
。
扩展类应仅覆盖问题createEntities($details)
中的测试函数。所以创建一个新的并从原始函数中复制代码。
另外,创建一个新函数create_record()
。
现在,在新createEntitied
内,调用您的create_record版本 - $this->create_record()
,而不是调用全局函数。
现在你可以嘲笑它!甚至因为这个类只用于测试,你甚至可以从中恢复任何你想要的东西,甚至不必现在就嘲笑它。
此类可以驻留在常规代码文件夹中,也可以作为测试类的邻居 - 因为它仅用于测试。
优点:
缺点:
createEntities
内的代码需要
被复制也许这不是最理想的,但应该完成工作。希望我帮忙。