我有这样的情况。我有一些第三方特质(我不想测试),并且我的特质使用此特质,并且在某些情况下运行第三方特质方法(在下面的示例中,我总是运行它)。
当我有这样的代码时:
use Mockery;
use PHPUnit\Framework\TestCase;
class SampleTest extends TestCase
{
/** @test */
public function it_runs_parent_method_alternative()
{
$class = Mockery::mock(B::class)->makePartial();
$class->shouldReceive('fooX')->once();
$this->assertSame('bar', $class->foo());
}
protected function tearDown()
{
Mockery::close();
}
}
trait X {
function foo() {
$this->something->complex3rdpartyStuff();
}
}
trait Y2 {
function foo() {
$this->fooX();
return 'bar';
}
}
class B {
use Y2, X {
Y2::foo insteadof X;
X::foo as fooX;
}
}
它可以正常工作,但是我不希望这样组织代码。在上述类的代码中,我同时使用了两个特征,但实际上我想测试的特征中的特征使用了开头提到的其他特征。
但是,当我有这样的代码时:
<?php
use Mockery;
use PHPUnit\Framework\TestCase;
class SampleTest extends TestCase
{
/** @test */
public function it_runs_parent_method()
{
$class = Mockery::mock(A::class)->makePartial();
$class->shouldReceive('fooX')->once();
$this->assertSame('bar', $class->foo());
}
protected function tearDown()
{
Mockery::close();
}
}
trait X {
function foo() {
$this->something->complex3rdpartyStuff();
}
}
trait Y {
use X {
foo as fooX;
}
function foo() {
$this->fooX();
return 'bar';
}
}
class A {
use Y;
}
我得到:
未定义的属性$ something
因此,在这种情况下,Mockery似乎不再嘲笑X :: foo方法。有没有办法用这样的代码编写这样的测试?
答案 0 :(得分:2)
到目前为止,尚无法模拟更深的别名方法。您可以使用本地方法代理别名的方法调用,并允许模拟受保护的方法。
检查下面的代码
use Mockery;
use PHPUnit\Framework\TestCase;
class SampleTest extends TestCase
{
/** @test */
public function it_runs_parent_method()
{
$mock = Mockery::mock(A::class)->shouldAllowMockingProtectedMethods()->makePartial();
$mock->shouldReceive('proxyTraitCall')->once();
$this->assertSame('bar', $mock->foo());
}
protected function tearDown()
{
Mockery::close();
}
}
trait X {
function foo() {
$this->something->complex3rdpartyStuff();
}
}
trait Y {
use X {
foo as fooX;
}
function foo() {
$this->proxyTraitCall();
return 'bar';
}
function proxyTraitCall() {
return $this->fooX();
}
}
如果您自动加载特征,可以尝试使用Mockery overload。
/** @test */
public function it_runs_parent_method()
{
$trait = Mockery::mock("overload:" . X::class);
$trait->shouldReceive('foo')->once();
$class = Mockery::mock(A::class)->makePartial();
$this->assertSame('bar', $class->foo());
}
Don't test implementation details.像使用它一样进行测试。
类用户必须只知道公共接口才能使用它,为什么测试应该有任何不同? 一个内部方法调用不同的事实是实现细节,并对此进行测试以破坏封装。如果某天您将从特质转换为类方法而不更改类行为,则即使外部类看起来相同,也将不得不修改测试。
摘自Dave Thomas和Andy Hunt的实用单元测试
大多数时候,您应该能够通过练习课堂来测试它 公共方法。如果有重要功能被隐藏 在私人或受保护的访问之后,可能是一个警告信号, 那里还有另一个班级努力奋斗。