Bir parametreye dayalı olarak farklı değerler döndürmek için PHPUnit MockObjects nasıl alabilirim?


141

Ben 'return value'onun argümanları ne olursa olsun döndüren bir PHPUnit sahte nesne var :

// From inside a test...
$mock = $this->getMock('myObject', 'methodToMock');
$mock->expects($this->any))
     ->method('methodToMock')
     ->will($this->returnValue('return value'));

Ne yapabilmek istiyorum sahte yöntemine iletilen bağımsız değişkenlere dayalı farklı bir değer döndürmektir. Gibi bir şey denedim:

$mock = $this->getMock('myObject', 'methodToMock');

// methodToMock('one')
$mock->expects($this->any))
     ->method('methodToMock')
     ->with($this->equalTo('one'))
     ->will($this->returnValue('method called with argument "one"'));

// methodToMock('two')
$mock->expects($this->any))
     ->method('methodToMock')
     ->with($this->equalTo('two'))
     ->will($this->returnValue('method called with argument "two"'));

Ancak bu, sahte argüman ile çağrılmazsa PHPUnit'in şikayet etmesine neden olur 'two', bu yüzden methodToMock('two')ilk tanımın üzerine yazıldığını varsayalım .

Benim sorum şu: Bir PHPUnit sahte nesne bağımsız değişkenleri dayalı farklı bir değer döndürmek için herhangi bir yolu var mı? Ve eğer öyleyse, nasıl?

Yanıtlar:


125

Bir geri arama kullanın. örneğin (doğrudan PHPUnit belgelerinden):

<?php
class StubTest extends PHPUnit_Framework_TestCase
{
    public function testReturnCallbackStub()
    {
        $stub = $this->getMock(
          'SomeClass', array('doSomething')
        );

        $stub->expects($this->any())
             ->method('doSomething')
             ->will($this->returnCallback('callback'));

        // $stub->doSomething() returns callback(...)
    }
}

function callback() {
    $args = func_get_args();
    // ...
}
?>

Geri aramada () istediğiniz işlemi yapın ve sonucu $ args değerine göre döndürün.


2
Belgelere bir bağlantı verebilir misiniz? "Google" ile bulamıyorum
Kris Erickson

6
Bir yöntemi, örneğin bir diziyi ileterek geri arama olarak kullanabileceğinizi unutmayın $this->returnCallback(array('MyClassTest','myCallback')).
Patrick Fisher

1
Ayrıca doğrudan bir kapak geçmek de mümkün olmalıdır
Ocramius

7
Bu sadece nadir durumlarda kullanılmalıdır. Geri aramada özel mantık gerektirmediği için bunun yerine returnValueMap kullanmanızı öneririm .
Herman J. Radtke III

1
Sana yeterince teşekkür edemem. Ayrıca, PHP 5.4'ten büyük sürümlerde, geri çağırma olarak anonim bir işlev kullanabilirsiniz. $this->returnCallback(function() { // ... })
2'de bmorenate

110

En son phpUnit docs dosyasından: "Bazen bir stubbed yöntemi, önceden tanımlanmış bir argümanlar listesine bağlı olarak farklı değerler döndürmelidir. Bağımsız değişkenleri karşılık gelen dönüş değerleriyle ilişkilendiren bir harita oluşturmak için returnValueMap () öğesini kullanabilirsiniz ."

$mock->expects($this->any())
    ->method('getConfigValue')
    ->will(
        $this->returnValueMap(
            array(
                array('firstparam', 'secondparam', 'retval'),
                array('modes', 'foo', array('Array', 'of', 'modes'))
            )
        )
    );


49

Benzer bir sorunum vardı (biraz farklı olmasına rağmen ... bağımsız değişkenlere dayalı farklı dönüş değerine ihtiyacım yoktu, ancak aynı işleve 2 argüman kümesinin geçildiğinden emin olmak için test etmek zorunda kaldım). Ben böyle bir şey kullanarak tökezledi:

$mock = $this->getMock();
$mock->expects($this->at(0))
    ->method('foo')
    ->with(...)
    ->will($this->returnValue(...));

$mock->expects($this->at(1))
    ->method('foo')
    ->with(...)
    ->will($this->returnValue(...));

Mükemmel değil, çünkü 2 foo () çağrısının sırasının bilinmesini gerektiriyor, ancak pratikte bu muhtemelen çok kötü değil .


28

Muhtemelen OOP tarzında bir geri arama yapmak istersiniz:

<?php
class StubTest extends PHPUnit_Framework_TestCase
{
    public function testReturnAction()
    {
        $object = $this->getMock('class_name', array('method_to_mock'));
        $object->expects($this->any())
            ->method('method_to_mock')
            ->will($this->returnCallback(array($this, 'returnCallback'));

        $object->returnAction('param1');
        // assert what param1 should return here

        $object->returnAction('param2');
        // assert what param2 should return here
    }

    public function returnCallback()
    {
        $args = func_get_args();

        // process $args[0] here and return the data you want to mock
        return 'The parameter was ' . $args[0];
    }
}
?>

16

Tam olarak sorduğunuz şey değil, ancak bazı durumlarda yardımcı olabilir:

$mock->expects( $this->any() ) )
 ->method( 'methodToMock' )
 ->will( $this->onConsecutiveCalls( 'one', 'two' ) );

onConsecutiveCalls - belirtilen sırayla bir değer listesi döndürür


4

Her öğenin bir dizi olduğu iki düzeyli dizi iletin:

  • ilki yöntem parametreleridir ve en azından dönüş değeridir.

misal:

->willReturnMap([
    ['firstArg', 'secondArg', 'returnValue']
])

2

Ayrıca, argümanı aşağıdaki gibi döndürebilirsiniz:

$stub = $this->getMock(
  'SomeClass', array('doSomething')
);

$stub->expects($this->any())
     ->method('doSomething')
     ->will($this->returnArgument(0));

Mocking belgelerinde görebileceğiniz gibi, yöntem returnValue($index)verilen argümanın döndürülmesine izin verir.


0

Bunun gibi birşey mi demek istedin?

public function TestSomeCondition($condition){
  $mockObj = $this->getMockObject();
  $mockObj->setReturnValue('yourMethod',$condition);
}

Bence bu SimpleTest kodu, PHPUnit değil. Ama hayır, elde etmek istediğim şey bu değil. Diyelim ki belirli bir sayı için bir kelime döndüren sahte bir nesnem vardı. Benim sahte yöntem 1 ile çağrıldığında "bir", 2 vb ile çağrıldığında "iki" dönmek gerekir. $
Ben Dowling

0

Ben de çalışamadım benzer bir sorun vardı (PHPUnit hakkında şaşırtıcı derecede az bilgi var). Benim durumumda, her testi ayrı test bilinen giriş ve bilinen çıkış yaptım. Ben-bir all-trades sahte nesne yapmak gerek olmadığını fark ettim, sadece belirli bir test için belirli bir ihtiyacım vardı, ve bu yüzden testleri ayrılmış ve ayrı bir kod olarak bireysel yönlerini test edebilirsiniz birimi. Bunun sizin için geçerli olup olmadığından emin değilim, ancak test etmeniz gereken şey bu.


Ne yazık ki bu benim durumumda işe yaramaz. Sahte, test ettiğim bir yönteme geçiriliyor ve test yöntemi, sahte argümanı farklı argümanlarla çağırıyor. Yine de sorunu çözemeyeceğinizi bilmek ilginç. Bu bir PHPUnit sınırlaması olabilir gibi görünüyor.
Ben Dowling

-1
$this->BusinessMock = $this->createMock('AppBundle\Entity\Business');

    public function testBusiness()
    {
        /*
            onConcecutiveCalls : Whether you want that the Stub returns differents values when it will be called .
        */
        $this->BusinessMock ->method('getEmployees')
                                ->will($this->onConsecutiveCalls(
                                            $this->returnArgument(0),
                                            $this->returnValue('employee')                                      
                                            )
                                      );
        // first call

        $this->assertInstanceOf( //$this->returnArgument(0),
                'argument',
                $this->BusinessMock->getEmployees()
                );
       // second call


        $this->assertEquals('employee',$this->BusinessMock->getEmployees()) 
      //$this->returnValue('employee'),


    }

-2

Deneyin :

->with($this->equalTo('one'),$this->equalTo('two))->will($this->returnValue('return value'));

Bu yanıt orijinal soru için geçerli değildir, ancak yaşadığım benzer bir sorunu detaylandırıyor: belirli bir parametre kümesinin sağlandığını doğrulayın . PHPUnit ile () her parametre için bir eşleştirici olmak üzere, birden fazla argüman kabul eder.
TaZ
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.