标签: phpunit

在PHPUnit中测试具有依赖项的对象

对于组成另一个对象作为其实现的一部分的对象,编写单元测试的最佳方法是什么,只有主要对象才会被测试?琐碎的例子:

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 phpunit unit-testing qa

9
推荐指数
2
解决办法
6205
查看次数

扩展PHPUnit:添加装饰器

上下文

我最近继承了一个编程良好的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脚本来使用我的东西而不是内置的东西. …

php phpunit

9
推荐指数
1
解决办法
1014
查看次数

单元测试Doctrine ODM

我开始编写Doctrine 2 Mongo ODM单元测试,但发现我的代码中没有一个好的策略来做到这一点.我想运行测试并实际持久保存对象,但我想让我的测试数据在tearDown中轻松删除.必须从我在注释中看到的内容中指定集合和数据库名称,并且不能覆盖它,因此我不能仅创建测试数据库并在以后擦除它.

有没有人有他们认为最佳测试方法的最佳实践或示例?

testing phpunit doctrine

9
推荐指数
1
解决办法
1429
查看次数

ZF2服务定位器和依赖注入

Zend的优秀人员以及一些博主推荐ZF2的新服务定位器/管理器,而不是内置的依赖注入系统.

我的问题是,将模拟对象注入服务是否可行/方便?我在模块的PHPUnit引导程序中看到了一些略显笨拙的尝试.但有没有一种方法可以使用这种服务系统,比如ZF1 + Yadif干净方便?

phpunit dependency-injection service-locator zend-framework2

9
推荐指数
1
解决办法
2999
查看次数

PHPUnit:在<ClassNameTest> .php中找不到类<ClassName>

我的智慧结束了.我必须阅读关于同一主题的每一个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,但没有快乐.你能辨别出什么是错的吗?如果您需要更多信息,请告诉我,我将编辑此帖子.提前致谢.

  • PHP 5.3.15
  • PHPUnit 3.7.13
  • OSX 10.8.2

php phpunit unit-testing

9
推荐指数
1
解决办法
4814
查看次数

为什么我在 Laravel 中运行测试时收到“CSRF 令牌不匹配”?

我想在不收到“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 csrf laravel

9
推荐指数
2
解决办法
4304
查看次数

PHPUnit 在 CI 中停滞

我们遇到了 PHPUnit 的问题,有时无法在 CI 中正确运行我们的测试套件。该行为表现为大约 1/3 的测试无法启动并且 CI 步骤超时。有趣的是,我们没有看到这种行为:

  1. 在我们的机器上本地
  2. 每次我们运行测试
  3. 与黄昏测试一起发生

我们的设置是使用 docker compose 运行测试。我们专门先启动应用容器的依赖,然后暂停30秒等待它们上来(即数据库)。

我试图解决的一些问题并没有产生影响:

  1. 在进程隔离打开的情况下运行测试。
  2. 将测试套件拆分为两个以运行更少的测试(两个拆分都有相同的问题)

测试在 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)

php phpunit unit-testing

9
推荐指数
1
解决办法
169
查看次数

xdebug.start_start_with_request=yes 如果调试客户端未侦听,则不会出现错误

我曾经对 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 中的错误报告对我来说似乎是一种肮脏的黑客行为,可能存在缺陷,而不是有效的解决方案。

如果没有此消息,我如何才能保持预期的行为?

phpunit xdebug xdebug-3

9
推荐指数
2
解决办法
9819
查看次数

Docker、PhpStorm 和 PHPUnit - 指定了自动加载器的值,但文件不存在

我正在尝试将我的 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 phpunit phpstorm docker

9
推荐指数
1
解决办法
5379
查看次数

Laravel 8.0 测试中刷新数据库时“没有活动事务”

使用 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)

php mysql phpunit laravel

9
推荐指数
2
解决办法
2万
查看次数