方法setValue()在类SomeClass中接受参数,并且无法为make断言获取此参数。
我可以为方法setValue()创建一个存根,它允许保存传递给此方法的参数吗?
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);
}
}
答案 0 :(得分:3)
关于如何测试设置是否有效,请参阅@Gordons回答。
您的单元测试应确保您的类的公共 API按预期工作。您不关心(为了测试)如何在内部存储您的值,因此您不需要需要对其进行断言。这样做也会让你的测试只测试你班级做什么而不是班级怎么做
重点是,在更改课程时不必更改测试而不影响其作用
为了论证,让我们说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的示例可能不是正确的,但它显示了如何非常好地测试行为(我希望)
答案 1 :(得分:2)
没有。 Mocks为replacements for Dependencies,而不是实际的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 :(得分:1)
您可以使用returnCallback执行任意代码,例如测试用例的测试助手方法。例如,如果setValueTester是测试用例中的一个方法,则此期望会将对模拟的setValue的调用重定向到它。 func_get_args可以使用参数。
$mock->expects($this->any())->method("setValue")->will($this->returnCallback(array($this,"setValueTester"));
答案 3 :(得分:1)
在这个简单的例子中,您可以指定希望传递给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 '));
}
}
我同意edorian的观点,你最好通过公共API测试课堂上的内容。直接测试内部实现意味着每次更改或重构时都会更新更多测试。