PHPUnit: how to save arguments passed to stub method

The setValue () method in the SomeClass class takes arguments and cannot return these arguments for the make statement.

Is it possible to create a stub for the setValue () method, which allows saving the arguments passed to this method?


class SomeClass {
  public function setValue($name, $value)
  {
    // do some stuff
  }
  public function doSomething(array $values)
  {
    foreach ($values as $name=>$value) {
      $this->setValue($name, trim($value));
    }
  }
}

class TestSomeClass extends PHPUnit_Framework_TestCase {
public function testDoSomething() { $mock = $this->getMock('SomeClass', array('setValue')); $mock->doSomething(array('v1'=>' string ')); // here need I need assert like this $this->assertEquals('string', $argumentPassedToSetValue); } }

+3
source share
4 answers

For how to check if the settings worked, see @Gordons.

I would like to argue that you do not need to verify this.

, API public . ( ), , . , , ,

, , , ,

let say SomeClass - , HTML.

class SomeClass {
  public function setValue($name, $value)
  {
    // do some stuff
  }

  public function doSomething(array $values)
  {
    foreach ($values as $name=>$value) {
      $this->setValue($name, trim($value));
    }
  }

  public function createHTML() 
  {
    $return = "";
    foreach($this->values as $key => $value) { 
         $return .= "<div is='$key'>$value</div>"; 
    }
    return $return;
  }

}

, , :

class SomeClassTest extends PHPUnit_Framework_TestCase {

    public function testHtmlGenerationWithTwoValuesSet() {
        $o = new SomeClass();
        $o->setValue("foo", "bar");
        $o->setValue("x", "y");
        $result = $o->createHTML();
        $this->assertSame(
             2,
             substr_count("<div>", $result),
             "There should be as many divs as there are values set"
        );
        $this->assertTrue(
             strpos("<div>bar</div>") !== false
             "String should contain a set value enclosed in divs"
        );
    }

}

: , . , .

html , , ()

+3

. Mocks , TestSubject.

setValue , assertAttributeEquals:

class SomeClass
{
    protected $foo;
    public function setFoo($val)
    {
        $this->foo = trim($val);
    }
}

class SomeClassTest extends PHPUnit_Framework_TestCase
{
    public function testSetFooTrimsArgument()
    {
        $testSubject = new SomeClass;
        $testSubject->setFoo('  bar  ');
        $this->assertAttributeEquals(
            'bar',  /* expected value */
            'foo',  /* attribute name */
            $testSubject
        );
    }
}

, ,

+2

returnCallback , . , setValueTester - , setValue . func_get_args.

$mock->expects($this->any())->method("setValue")->will($this->returnCallback(array($this,"setValueTester"));
+1
source

In this simple case, you can specify the argument that you expect to pass to setValue().

class TestSomeClass extends PHPUnit_Framework_TestCase
{
  public function testDoSomething()
  {
    $mock = $this->getMock('SomeClass', array('setValue'));
    $mock->expects($this->once())->method('setValue')->with('v1', 'string');
    $mock->doSomething(array('v1'=>'  string  '));
  }
}

I agree with edorian, however, that you better test what comes out of the class through the public API. Testing an internal implementation directly means updating more tests with every change or reorganization.

+1
source

All Articles