8

これは、私がテスト スイートを作成しているクラスのコンストラクターです (mysqli を拡張します)。

function __construct(Config $c)
{
    // store config file
    $this->config = $c;

    // do mysqli constructor
    parent::__construct(
        $this->config['db_host'],
        $this->config['db_user'],
        $this->config['db_pass'],
        $this->config['db_dbname']
    );
}

Configコンストラクターに渡されるクラスは、php に組み込まれたインターフェースを実装しますarrayaccess

class Config implements arrayaccess{...}

Configオブジェクトをモック/スタブするにはどうすればよいですか? どちらを使用する必要があり、その理由は?

前もって感謝します!

4

2 に答える 2

16

配列からインスタンスを簡単に作成できる場合はConfig、それが私の好みです。実用的な場所でユニットを分離してテストしたい場合は、 のような単純な共同作業者Configは、テストで使用するのに十分安全でなければなりません。それをセットアップするコードは、同等のモック オブジェクトよりもおそらく読み書きが容易になります (エラーが発生しにくくなります)。

$configValues = array(
    'db_host' => '...',
    'db_user' => '...',
    'db_pass' => '...',
    'db_dbname' => '...',
);
$config = new Config($configValues);

ArrayAccessそうは言っても、他のオブジェクトと同じように実装するオブジェクトをモックします。

$config = $this->getMock('Config', array('offsetGet'));
$config->expects($this->any())
       ->method('offsetGet')
       ->will($this->returnCallback(
           function ($key) use ($configValues) {
               return $configValues[$key];
           }
       );

atを使用して特定のアクセス順序を強制することもできますが、その方法ではテストが非常に脆弱になります。

于 2012-05-15T23:32:51.343 に答える
1

質問が出されてから 8 年後、最初に回答されてから 5 年後、私は同じ質問をして同様の結論に達しました。これは私が行ったことであり、基本的にはDavidの受け入れられた回答の2番目の部分と同じですが、PHPUnitの新しいバージョンを使用しています。

基本的に、ArrayAccessインターフェイス メソッドをモックできます。offsetGetと の両方をモックしたい可能性があることを覚えておく必要がありますoffsetExists(配列キーを使用する前に、その存在を常に確認する必要があります。そうE_NOTICEしないと、コードが存在しない場合にエラーや予期しない動作が発生する可能性があります)。



$thingyWithArrayAccess = $this->createMock(ThingyWithArrayAccess::class);

$thingyWithArrayAccess->method('offsetGet')
     ->with('your-offset-here')
     ->willReturn('test-value-1');

$thingyWithArrayAccess->method('offsetExists')
     ->with($'your-offset-here')
     ->willReturn(true);

もちろん、次のように、テストで実際の配列を使用することもできます。


$theArray = [
    'your-offset-here-1' => 'your-mock-value-for-offset-1',
];

$thingyWithArrayAccess = $this->createMock(ThingyWithArrayAccess::class);

$thingyWithArrayAccess->method('offsetGet')
     ->willReturnCallback(
          function ($offset) use ($theArray) {
              return $theArray[$offset];
          }
     );

$thingyWithArrayAccess->method('offsetExists')
     ->willReturnCallback(
          function ($offset) use ($theArray) {
              return array_key_exists($offset, $theArray);
          }
     );

于 2020-07-29T16:33:23.310 に答える