47

私は現在、PHPUnit を使用して、自分が書いているものと一緒にテストを開発しようとしていますが、現在、Session Manager の作成に取り組んでおり、そうするのに問題があります...

セッション処理クラスのコンストラクタは次のとおりです。

private function __construct()
{
    if (!headers_sent())
    {
        session_start();
        self::$session_id = session_id();
    }
}

ただし、PHPUnit はテストを開始する前にテキストを送信するため、HTTP「ヘッダー」が送信されているため、このオブジェクトのテストは失敗したテストを返します...

4

11 に答える 11

38

さて、あなたのセッションマネージャーは基本的に設計上壊れています。何かをテストできるようにするには、それを副作用から分離できなければなりません。echo残念ながら、PHP はグローバル状態 ( 、header、など)exitを自由に使用できるように設計されています。session_start

あなたができる最善のことは、実行時に交換できるコンポーネントの副作用を分離することです。そうすれば、実際の副作用を持つアダプターをライブ コードで使用しながら、テストでモック オブジェクトを使用できます。これは、あなたが使用していると思われるシングルトンではうまく機能しないことがわかります。そのため、共有オブジェクトをコードに配布するには、他のメカニズムを使用する必要があります。静的レジストリから始めることもできますが、多少の学習が必要ない場合は、さらに優れたソリューションがあります。

それができない場合は、いつでも統合テストを作成するオプションがあります。例えば。に相当する PHPUnit を使用しますWebTestCase

于 2008-10-10T08:17:01.270 に答える
20

phpunitのブートストラップファイルを作成します。これは次の呼び出しを行います。

session_start();

次に、次のようにphpunitを起動します。

phpunit --bootstrap pathToBootstrap.php --anotherSwitch /your/test/path/

ブートストラップファイルは他のすべての前に呼び出されるため、ヘッダーは送信されておらず、すべてが正常に機能するはずです。

于 2009-11-09T13:39:01.667 に答える
19

phpUnit はテストの実行時に出力を出力するため、最初のテストでも headers_sent() が true を返します。

テスト スイート全体でこの問題を解決するには、セットアップ スクリプトで ob_start() を使用するだけです。

たとえば、phpUnit によって最初に読み込まれる AllTests.php という名前のファイルがあるとします。そのスクリプトは次のようになります。

<?php

ob_start();

require_once 'YourFramework/AllTests.php';

class AllTests {
    public static function suite() {
        $suite = new PHPUnit_Framework_TestSuite('YourFramework');
        $suite->addTest(YourFramework_AllTests::suite());
        return $suite;
    }
}
于 2010-10-30T15:44:01.037 に答える
13

私は同じ問題を抱えていましたが、次のように --stderr フラグを付けて phpunit を呼び出すことで解決しました:

phpunit --stderr /path/to/your/test

それが誰かを助けることを願っています!

于 2014-07-16T10:33:58.930 に答える
5

「正しい」解決策は、PHPのセッション関連関数のラッパーである非常に単純なクラス(テストする必要がないほど単純)を作成しsession_start()、などを直接呼び出す代わりにそれを使用することだと思います。

実際のステートフルでテスト不可能なセッション クラスの代わりに、テスト パス モック オブジェクトで。

private function __construct(SessionWrapper $wrapper)
{
   if (!$wrapper->headers_sent())
   {
      $wrapper->session_start();
      $this->session_id = $wrapper->session_id();
   }
}
于 2008-11-12T00:01:40.543 に答える
1

XDebugオプションを誰もリストしていないのはなぜだろうと思っています:

/**
 * @runInSeparateProcess
 * @requires extension xdebug
 */
public function testGivenHeaderIsIncludedIntoResponse()
{
    $customHeaderName = 'foo';
    $customHeaderValue = 'bar';

    // Here execute the code which is supposed to set headers
    // ...

    $expectedHeader = $customHeaderName . ': ' . $customHeaderValue;
    $headers = xdebug_get_headers();

    $this->assertContains($expectedHeader, $headers);
}
于 2015-10-30T22:25:57.583 に答える
0

ブートストラップファイルの作成は、4つの投稿が戻ってきたことを指摘しましたが、これを回避する最もクリーンな方法のようです。

多くの場合、PHPを使用する場合は、維持する必要があり、非常に小さくまとめられたレガシープロジェクトにある種のエンジニアリング分野を追加しようとします。ゴミの山全体を捨ててやり直す時間(または権限)がないため、troelsknによる最初の回答が常に可能であるとは限りません。(最初の設計に戻ることができれば、PHPを完全に捨てて、Web開発の世界でこのCOBOLを永続化するのを助けるのではなく、rubyやpythonなどのより現代的なものを使用できます。)

全体でsession_startまたはsetcookieを使用するモジュールの単体テストを作成しようとしている場合は、ブーストラップファイルでセッションを開始するよりも、これらの問題を回避できます。

于 2009-12-04T09:53:37.377 に答える
0

私は今ブートストラップをユニットテストしているので(そうです、ほとんどの人はそうしないことを知っています)、同じ問題(header()とsession_start()の両方)に遭遇しています。私が見つけた解決策はかなり単純です。ユニットテストのブートストラップで定数を定義し、ヘッダーを送信する前、またはセッションを開始する前に定数を確認するだけです。

// phpunit_bootstrap.php
define('UNITTEST_RUNNING', true);

// bootstrap.php (application bootstrap)
defined('UNITTEST_RUNNING') || define('UNITTEST_RUNNING', false);
.....
if(UNITTEST_RUNNING===false){
    session_start();
}

これは設計上完全ではないことに同意しますが、既存のアプリケーションを単体テストしているため、大きなパーツを書き直すことは望ましくありません。また、同じロジックを使用して、__ call()および__set()マジックメソッドを使用してプライベートメソッドをテストします。

public function __set($name, $value){
    if(UNITTEST_RUNNING===true){
       $name='_' . $name;
       $this->$name=$value;
    }
    throw new Exception('__set() can only be used when unittesting!');
 }
于 2011-10-19T13:39:17.077 に答える
0

テストを開始する前に出力バッファリングを使用できませんか? 出力されるすべてをバッファリングする場合、その時点でクライアントに出力がまだ送信されていないため、ヘッダーの設定に問題はありません。

OB がクラス内のどこかで使用されている場合でも、それはスタック可能であり、OB は内部で行われていることに影響を与えるべきではありません。

于 2008-10-10T06:12:22.923 に答える
0

私の知る限り、Zend Framework は Zend_Session パッケージのテストに同じ出力バッファリングを使用しています。彼らのテストケースを見て、始めることができます。

于 2008-10-10T07:40:33.543 に答える