对于组成另一个对象作为其实现的一部分的对象,编写单元测试的最佳方法是什么,只有主要对象才会被测试?琐碎的例子:
class myObj {
public function doSomethingWhichIsLogged()
{
// ...
$logger = new logger('/tmp/log.txt');
$logger->info('some message');
// ...
}
}
Run Code Online (Sandbox Code Playgroud)
我知道可以设计对象以便可以注入logger对象依赖项并因此在单元测试中进行模拟,但情况并非总是如此 - 在更复杂的场景中,您需要组合其他对象或调用静态方法.
由于我们不想测试logger对象,只有myObj,我们如何进行?我们用测试脚本创建一个stubbed"double"吗?就像是:
class logger
{
public function __construct($filepath) {}
public function info($message) {}
}
class TestMyObj extends PHPUnit_Framework_TestCase
{
// ...
}
Run Code Online (Sandbox Code Playgroud)
这对于小对象来说似乎是可行的,但对于更复杂的API而言,这将是一个痛苦,其中SUT依赖于返回值.另外,如果你想测试对依赖项对象的调用,你可以使用模拟对象吗?有没有办法模拟由SUT实例化的对象而不是传入?
我已经阅读了关于模拟的手册页,但它似乎并没有涵盖这种依赖是由组合而不是聚合的情况.你怎么做呢?
我最近继承了一个编程良好的PHP应用程序(sarcasm)的开发和维护.该应用程序基于商业软件(我不会命名),并且有一层基于它的定制(我们的).
不幸的是,这个应用程序使用了大量的全局和单例(双关语).我已经为我们覆盖的所有事情构建了测试用例.然而,很多事情都依赖于一些全球状态,这可能会导致竞争条件和各种奇怪的东西.
为了捕获大部分这些奇怪的东西(我喜欢称之为),我已经构建了一个PHPUnit TestDecorator,[如手册中所述] [1].这个:
class PHPUnit_Extensions_Randomizer extends PHPUnit_Extensions_TestDecorator
{
public function __construct(PHPUnit_Framework_Test $test)
{
$tests = $test->tests();
$shuffle = array();
foreach ($tests as $t) {
if ($t instanceof PHPUnit_Framework_TestSuite) {
$shuffle = array_merge($shuffle, $t->tests());
} else {
$shuffle[] = $t;
}
}
shuffle($shuffle);
$suite = new PHPUnit_Framework_TestSuite();
foreach ($shuffle as $t) $suite->addTest($t);
parent::__construct($suite);
}
}
Run Code Online (Sandbox Code Playgroud)
它基本上随机化测试顺序,以确保测试不依赖于可能正确或可能不正确的全局状态.
当来测试我的自定义装饰器时出现了问题.我没有在手册,谷歌或Stack Overflow中的任何地方找到如何加载它.
在分析代码时,我看到PHPUnit本身正在实例化方法中的RepeatedTest装饰器TextUI_TestRunner::doRun().我知道我可以子类化TestRunner,覆盖doRun(),安排我的装饰器被创建然后只需调用parent::doRun()我的装饰器实例作为参数,覆盖TextUI_Command并创建一个新的CLI脚本来使用我的东西而不是内置的东西. …
我开始编写Doctrine 2 Mongo ODM单元测试,但发现我的代码中没有一个好的策略来做到这一点.我想运行测试并实际持久保存对象,但我想让我的测试数据在tearDown中轻松删除.必须从我在注释中看到的内容中指定集合和数据库名称,并且不能覆盖它,因此我不能仅创建测试数据库并在以后擦除它.
有没有人有他们认为最佳测试方法的最佳实践或示例?
Zend的优秀人员以及一些博主推荐ZF2的新服务定位器/管理器,而不是内置的依赖注入系统.
我的问题是,将模拟对象注入服务是否可行/方便?我在模块的PHPUnit引导程序中看到了一些略显笨拙的尝试.但有没有一种方法可以使用这种服务系统,比如ZF1 + Yadif干净方便?
phpunit dependency-injection service-locator zend-framework2
我的智慧结束了.我必须阅读关于同一主题的每一个SO问题,但没有快乐.
我无法让phpUnit正常工作.我已经使用PEAR成功安装了phpUnit及其依赖项.我还修改了我的php.ini文件并将路径添加到包含路径的phpUnit :(".:/ php/includes:usr/lib/php/pear").
为了测试phpunit是否有效,我已经复制了这个简单的类,所以MyClassTest.php如下:
class MyClassTest extends PHPUnit_Framework_TestCase
{
public function testCalculate()
{
$this->assertEquals(2, 1 + 1);
}
}
Run Code Online (Sandbox Code Playgroud)
运行"phpunit MyClassTest"会产生以下输出:(运行"phpunit MyTestClass MyTestClass.php"产生相同的结果);
class MyClassTest extends PHPUnit_Framework_TestCase
{
public function testCalculate()
{
$this->assertEquals(2, 1 + 1);
}
}
PHPUnit 3.7.13 by Sebastian Bergmann.
Class 'MyClassTest' could not be found in 'MyClassTest.php'.
Run Code Online (Sandbox Code Playgroud)
我想不出什么是错的.我已经尝试卸载并重新安装phpunit/PHPUnit,但没有快乐.你能辨别出什么是错的吗?如果您需要更多信息,请告诉我,我将编辑此帖子.提前致谢.
我想在不收到“CSRF 令牌不匹配”异常的情况下运行我的测试。在 laravel 文档中指出:
运行测试时,CSRF 中间件会自动禁用。
抛出异常的代码行如下所示:
$response = $this->json('POST', route('order.create'), [
'product_id', $product->id
]);
Run Code Online (Sandbox Code Playgroud)
为了运行测试,我在我的 zsh 终端中工作:
php artisan test --env=testing
Run Code Online (Sandbox Code Playgroud)
这是我的测试课:
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Tests\TestCase;
class SessionCartTest extends TestCase
{
public function testExample()
{
$product = \App\Product::inRandomOrder()->first();
$response = $this->postJson(route('order.insert'), [
'product_id' => $product->id,
]);
$response->assertStatus(200); // here I receive 419
}
}
Run Code Online (Sandbox Code Playgroud)
我做错了什么,我该如何解决?我正在使用 Laravel 7。
我们遇到了 PHPUnit 的问题,有时无法在 CI 中正确运行我们的测试套件。该行为表现为大约 1/3 的测试无法启动并且 CI 步骤超时。有趣的是,我们没有看到这种行为:
我们的设置是使用 docker compose 运行测试。我们专门先启动应用容器的依赖,然后暂停30秒等待它们上来(即数据库)。
我试图解决的一些问题并没有产生影响:
测试在 Github Actions 中运行,这使得机器可以使用大约 7 gig 的内存以及多个内核。
同样有趣的是,基于黄昏的测试从未像这样停滞不前,尽管它们使用相同的 docker-compose 文件但具有附加服务(如 Selenium)。
我不确定这是否有明确的答案,但我现在不知道下一步要尝试什么(没有自己托管 GitHub 操作运行程序)。
失败测试的输出如下所示:
+ sleep 30
+ docker-compose -f docker-compose.ci.yml run --rm postgres pg_isready -h postgres -d testing -U testing -t 30
postgres:5432 - accepting connections
+ docker-compose -f docker-compose.ci.yml run --no-deps backend phpunit '--filter=/::test[J-Z|j-z]/' --testdox
Pulling backend (***.dkr.ecr.ap-southeast-2.amazonaws.com/builder:acb548c6125ad97e57e8070c414644c7e6f385f5)...
acb548c6125ad97e57e8070c414644c7e6f385f5: Pulling from builder
Digest: sha256:c84a53dbb201b809a2325a93c52d4a362eefa6de64ab98f759e43c5dd363aac2
Status: Downloaded newer image …Run Code Online (Sandbox Code Playgroud) 我曾经对 Xdebug 2 有以下配置:
xdebug.default_enable=1
当没有调试客户端正在侦听时,Xdebug 不会减慢执行速度,但是当我需要调试某些内容时,我只需在 PhpStorm 中启用侦听并刷新页面即可。为此不需要浏览器扩展。这同样适用于调试 CLI 应用程序,它确实有效。
我尝试使用 Xdebug 3 实现相同的效果,配置如下:
xdebug.mode=debug
xdebug.start_start_with_request=yes
Run Code Online (Sandbox Code Playgroud)
它的工作原理相同,但每次当我在 PhpStorm 中禁用调试侦听并运行 CLI 命令时,我都会收到以下错误严重程度的消息:
Xdebug: [Step Debug] Could not connect to debugging client. Tried: 172.17.0.1:9003 (through xdebug.client_host/xdebug.client_port) :-(
Run Code Online (Sandbox Code Playgroud)
这是我可以忍受的,但它也会使 PHPUnit 测试失败beStrictAboutOutputDuringTests="true"。
如果我使用过,升级指南建议使用,但这不是有效的替代品。xdebug.module=developxdebug.default_enable=1
完全沉默所有 Xdebug 日志,甚至禁用此评论建议的 PHP 中的错误报告对我来说似乎是一种肮脏的黑客行为,可能存在缺陷,而不是有效的解决方案。
如果没有此消息,我如何才能保持预期的行为?
我正在尝试将我的 PhpStorm 调试器与 PHPUnit 连接。我正在使用 Docker env,并且 docker PHPUnit 内部工作正常。问题是当我单击“测试”目录 PPM -> 运行测试时
我懂了:
[docker://environment_php_8_fpm:latest/]:php /opt/.phpstorm_helpers/phpunit.php --no-configuration /opt/project/src/tests
Testing started at 16:19 ...
The value of autoloader is specified, but file doesn't exist '/home/kuba/Work/CodeProjects/advertisement-crawler/src/vendor/autoload.php'
Process finished with exit code 1
Run Code Online (Sandbox Code Playgroud)
我试图在谷歌中找到解决方案,但很难找到有用的东西。
@edit此外,我提供了新路径,在单击刷新新路径后我得到了这个路径是:/opt/project/src/vendor/autoload.php

现在,在 phpstorm 中运行此命令后,我收到了新的错误消息
[docker://environment_php_8_fpm:latest/]:php /opt/.phpstorm_helpers/phpunit.php --configuration /opt/project/src/phpunit.xml
Testing started at 18:48 ...
Fatal error: Uncaught Error: Class "PHPUnit_TextUI_ResultPrinter" not found in /opt/.phpstorm_helpers/phpunit.php on line 231
Error: Class "PHPUnit_TextUI_ResultPrinter" not found in /opt/.phpstorm_helpers/phpunit.php on line 231
Call Stack:
0.0006 …Run Code Online (Sandbox Code Playgroud) 使用 php 8.0.2 和 Laravel 8.37.0,我正在运行测试,其中每个测试都应该刷新数据库数据,因为每个测试都有冲突的数据(由于唯一的约束)。
将内存数据库与 SQLite 一起使用,这是可行的,但是当我切换到 MySQL (v8.0.23) 时,我收到下一个错误:
1) Tests\Feature\Controllers\AuthControllerTest::testSuccessLogin
PDOException: There is no active transaction
Run Code Online (Sandbox Code Playgroud)
并且此后的测试由于数据已插入且测试后未清除而失败。
我想做的测试是:
<?php
namespace Tests\Feature\Controllers;
use App\Models\User;
use App\Models\User\Company;
use App\Repositories\UserRepository;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class AuthControllerTest extends TestCase
{
use RefreshDatabase;
protected array $connectionsToTransact = ['mysql'];
public function testSuccessLogin(): void
{
$this->artisan('migrate-data');
/** @var User $user */
$user = User::factory()->create([
'email' => 'test@website.com'
]);
$this->app->bind(UserRepository::class, function() use ($user) {
return new UserRepository($user, new Company());
});
$loginResponse = $this->post('/api/login', [ …Run Code Online (Sandbox Code Playgroud)