php - 测试重写的特征方法执行
问题描述
我有这样的情况。我有一些第 3 方特征(我不想测试),并且我有使用此特征的特征,并且在某些情况下运行第 3 方特征方法(在下面的示例中,我总是运行它)。
当我有这样的代码时:
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;
}
}
它会正常工作,但我不希望代码像这样组织。在上面的类代码中,我使用了这两个特征,但在代码中我想测试实际上 trait 使用了开头提到的其他特征。
但是,当我有这样的代码时:
<?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 方法了。有没有办法用这样组织的代码编写这样的测试?
解决方案
到目前为止,还不可能模拟更深层次的别名方法。您可以使用本地方法代理别名方法调用并允许模拟受保护的方法。
检查下面的代码
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();
}
}
如果你自动加载 trait,你可以尝试使用 Mockery重载它。
/** @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());
}
不要测试实现细节。像使用它一样测试它。
类用户只需要知道公共接口才能使用它,为什么测试应该有所不同?事实上,一个内部方法调用不同的一个是实现细节,并且测试这会破坏封装。如果有一天你会在不改变类行为的情况下从 trait 切换到类方法,那么即使外部的类看起来相同,你也必须修改测试。
摘自Dave Thomas 和 Andy Hunt 的实用单元测试
大多数时候,您应该能够通过执行其公共方法来测试一个类。如果有重要的功能隐藏在私有或受保护的访问之后,那可能是一个警告信号,表明那里有另一个班级正在努力摆脱。
推荐阅读
- javascript - drupal8 使用 java 脚本根据 from_date 显示 to_date - 未显示在表单上
- c++ - 为什么这段代码没有输出以及如何回收内存?
- excel - 从 Excel VBA 在 OneDrive 上创建文本文件
- javascript - 如何使用带有 Google Apps 脚本的主列表更新特定列中特定范围的数据验证?
- javascript - 在对象中添加字符并返回其计数输出
- has-and-belongs-to-many - CakePHP 4.x:如何创建一组表单控件来列出 HABTM(通过)关联中的所有值?
- javascript - 如何在 requestAnimationFrame 中使用多个线程来调用 Web Assembly 函数?
- javascript - 如何将模拟器连接到 redux-saga-firebase 应用程序
- swift - 使用 SwiftUI 更改 macOS 窗口级别(制作浮动窗口)
- c++ - 如何读取目标和约束的系数和指标?