我在Laravel中设置了以下内容:
/app/controllers/MyController.php
:
class MyController extends BaseController {
const MAX_FILE_SIZE = 10000;
// ....
}
/app/tests/MyControllerTest.php
:
class MyControllerTest extends TestCase {
public function myDataProvider() {
return [
[ MyController::MAX_FILE_SIZE ]
];
}
/**
* @dataProvider myDataProvider
*/
public function testMyController($a) {
// Just an example
$this->assertTrue(1 == 1);
}
}
但是,当我运行vendor/bin/phpunit
时,我收到以下错误:
PHP Fatal error: Class 'Controller' not found in /home/me/my-app/app/controllers/BaseController.php on line 3 Fatal error: Class 'Controller' not found in /home/me/my-app/app/controllers/BaseController.php on line 3
如果删除MyController
中对myDataProvider()
类的引用并将其替换为文字常量,则测试成功完成。
此外,我可以在实际的MyController::MAX_FILE_SIZE
方法中放置testMyController()
的引用,测试也会成功完成。
在调用数据提供程序方法之后 之前,似乎没有设置Laravel框架类的自动加载设置,但之前实际的测试方法是调用。 有没有解决方法,以便我可以从PHPUnit数据提供程序中访问Laravel框架类?
注意:我直接从命令行调用PHPUnit,而不是从IDE(例如NetBeans)调用。我知道有些人对此有疑问,但我认为这不适用于我的问题。
答案 0 :(得分:18)
正如this answer所暗示的那样,这似乎与PHPUnit在任何测试用例中调用任何数据提供者和setUp()
方法的顺序有关。
PHPUnit将在运行任何测试之前调用数据提供程序方法。在每次测试之前,它还会在测试用例中调用setUp()
方法。 Laravel挂钩setUp()
方法来调用$this->createApplication()
,这会将控制器类添加到' include路径'这样它们就可以正确自动加载。
由于数据提供程序方法在此之前运行,因此对数据提供程序内的控制器类的任何引用都会失败。通过将测试类修改为以下内容,可以解决这个问题:
class MyControllerTest extends TestCase {
public function __construct($name = null, array $data = array(), $dataName = '') {
parent::__construct($name, $data, $dataName);
$this->createApplication();
}
public function myDataProvider() {
return [
[ MyController::MAX_FILE_SIZE ]
];
}
/**
* @dataProvider myDataProvider
*/
public function testMyController($a) {
// Just an example
$this->assertTrue(1 == 1);
}
}
这将在运行数据提供程序方法之前调用createApplication()
,因此有一个有效的应用程序实例将允许正确自动加载相应的类。
这似乎有效,但我不确定它是否是最好的解决方案,或者它是否可能导致任何问题(尽管我无法想到为什么它应该出现问题)。
答案 1 :(得分:11)
如果您在dataProvider方法中创建应用程序,测试将更快地初始化,特别是如果您有大量要测试的项目。
import win32api
import win32file
if sys.platform == 'win32':
return [drive for drive in win32api.GetLogicalDriveStrings() if
re.match(r"^[A-Z]+", drive) and win32file.GetDriveType(drive + ":" + "//") == win32file.DRIVE_FIXED]
答案 2 :(得分:1)
性能警告(尤其是如果您打算在dataProviders中使用工厂的话):
如this article所述:
测试运行器通过扫描所有测试来构建测试套件 目录[…]当 找到
@dataProvider
批注,引用的数据提供者为 执行后,将创建一个TestCase并将其添加到TestSuite中,以用于 提供程序中的每个数据集。[…]
如果您在数据提供程序中使用工厂方法,则这些 工厂将使用此数据提供程序为每个测试运行一次 在您进行首次测试之前,甚至需要运行。因此,十项测试使用的数据提供者[…] 将在您第一次运行之前运行十次 测试甚至运行。这可能会大大减慢时间,直到您 第一次测试执行。甚至[…]使用
phpunit --filter
, 每个数据提供者仍将运行多次。测试后进行过滤 套件已生成,因此之后 数据提供者已执行。
以上文章建议从dataProvider返回闭包,并在测试中执行该闭包:
/**
* @test
* @dataProvider paymentProcessorProvider
*/
public function user_can_charge_an_amount($paymentProcessorProvider)
{
$paymentProcessorProvider();
$paymentProcessor = $this->app->make(PaymentProviderContract::class);
$paymentProcessor->charge(2000);
$this->assertEquals(2000, $paymentProcessor->totalCharges());
}
public function paymentProcessorProvider()
{
return [
'Braintree processor' => [function () {
$container = Container::getInstance();
$container->bind(PaymentProviderContract::class, BraintreeProvider::class);
}],
...
];
}