sam*_*ime 14 php phpunit unit-testing mocking
有没有办法用PHPUnit创建一个mock类,然后我可以使用它的类名创建一个新的实例?
我有一个定义两种方法的接口.就像是:
interface FooInterface {
function getA();
function getB();
}
Run Code Online (Sandbox Code Playgroud)
然后我有另一个接受类名的类,创建该类的实例,检查它是否是它所期望的实例(FooInterface),然后在该类上调用两个方法来获取一些信息.
class FooInfo {
protected $a;
protected $b;
public function __construct($fooClass) {
$foo = new $fooClass;
if (!($foo instanceof FooInterface)) {
throw new \Exception();
}
$this->a = $foo->getA();
$this->b = $foo->getB();
}
}
Run Code Online (Sandbox Code Playgroud)
我知道如何模拟一个对象就好了.问题是,因为这个类接受一个类名,而不是一个对象(它是一个Manager的一部分,根据需要创建给定类的实例),我不能使用普通的模拟对象.
我试着制作一个模拟对象,然后使用该类名.它似乎创造了对象很好,甚至似乎有我嘲笑的功能.但是,它似乎没有遵循我稍后设置的will($ this-> returnValue('myValue'))部分.
public function testConstruct()
{
$foo = $this->getMockForAbstractClass('Foo', array('getA', 'getB'));
$foo->expects($this->any())->method->('getA')->will($this->returnValue('a'));
$foo->expects($this->any())->method->('getB')->will($this->returnValue('b'));
$copyClass = get_class($foo);
$copy = new $copyClass();
// Passes
$this->assertTrue(method_exists($copy, 'getA');
// Fails, $copy->getA() returns null.
$this->assertEquals($copy->getA(), $foo->getA());
}
Run Code Online (Sandbox Code Playgroud)
因此,它确实具有被模拟的函数,但它们都返回null.
有任何想法吗?
mar*_*kus 14
new
在类的构造函数中使用关键字是一个相当糟糕的习惯,完全出于您现在遇到的原因,即使您的灵活用例也是如此.
您的测试将无法工作,因为您创建的模拟将永远不会被使用,因为您的类将始终创建注入的类名的真实实例.
也就是说,你想做的事情可以通过padraic的优秀模拟库嘲弄来完成!你需要的是'实例模拟':
$mock = \Mockery::mock('overload:MyNamespace\MyClass');
Run Code Online (Sandbox Code Playgroud)
您可以定义您对该模拟的期望,该模拟将在实例化后立即传输到真实对象.
将mockery与phpUnit集成在一起很简单,并在项目自述文件中得到了很好的解释.
顺便说一下.每个单元测试应该最佳地只做一个断言!