Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/247.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/laravel/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 如何对Laravel中调用另一个模型的方法进行单元测试_Php_Laravel_Unit Testing_Phpunit - Fatal编程技术网

Php 如何对Laravel中调用另一个模型的方法进行单元测试

Php 如何对Laravel中调用另一个模型的方法进行单元测试,php,laravel,unit-testing,phpunit,Php,Laravel,Unit Testing,Phpunit,我是测试和编写可测试代码的新手,我想了解一下处理这个简单场景的正确方法。我读过其他类似标题的问题和答案,但它们似乎没有对我的问题给出明确的答案 我有一个控制器,它在我的Picking类的实例上调用shipped()方法: class MyController extends \BaseController { public function controllerMethod() { $picking = new Picking; $picking->

我是测试和编写可测试代码的新手,我想了解一下处理这个简单场景的正确方法。我读过其他类似标题的问题和答案,但它们似乎没有对我的问题给出明确的答案

我有一个控制器,它在我的
Picking
类的实例上调用
shipped()
方法:

class MyController extends \BaseController {

    public function controllerMethod() {
        $picking = new Picking;
        $picking->shipped($shipmentData);
    }
}
拾取
模型如下所示:

class Picking extends \Eloquent {

    public function order() {
        return $this->belongsTo('Order');
    }    

    public function shipped($shipmentData) {
        $this->carrier = $shipmentData['Carrier'];
        $this->service = $shipmentData['Service'];
        $this->is_shipped = true;
        $this->save();

        $this->order->pickingShipped();
    }
}
$order->expects($this->once())->method('pickingShipped')
class Picking extends \Eloquent {

    public function order() {
        return $this->belongsTo('Order');
    }    

    public function shipped(Order $order, $shipmentData) {
        $this->carrier = $shipmentData['Carrier'];
        $this->service = $shipmentData['Service'];
        $this->is_shipped = true;
        $this->save();

        $order->pickingShipped();
    }
}
$picking = new Picking;
$picking->shipped($picking->order, $shipmentData);
如您所见,此
shipped()
方法保存一些数据,然后在其相关的
Order
上调用
pickingShipped()
方法

现在,我正在尝试为
shipped()
方法编写一个测试,但我不确定是否有合适的方法来实现这一点。我读过关于嘲弄的书,但我不知道这是否是一种需要嘲弄的情况。我想到了一些可能的解决办法,但我不确定其中是否有正确的

1)重新排列代码,以便控制器调用
pickingShipped()
方法,允许将其从
shipped()
方法中删除,从而简化测试。

例如,
shipped()
方法的最后一行将被删除,控制器代码将更改为:

$picking = new Picking;
$picking->shipped($shipmentData);
$picking->order->pickingShipped();
2)在测试中,在
order
上使用模拟方法,以便测试可以简单地确认调用了
pickingShipped()
方法。

与所解释的内容大致相同的东西。这意味着测试可以做如下操作:

class Picking extends \Eloquent {

    public function order() {
        return $this->belongsTo('Order');
    }    

    public function shipped($shipmentData) {
        $this->carrier = $shipmentData['Carrier'];
        $this->service = $shipmentData['Service'];
        $this->is_shipped = true;
        $this->save();

        $this->order->pickingShipped();
    }
}
$order->expects($this->once())->method('pickingShipped')
class Picking extends \Eloquent {

    public function order() {
        return $this->belongsTo('Order');
    }    

    public function shipped(Order $order, $shipmentData) {
        $this->carrier = $shipmentData['Carrier'];
        $this->service = $shipmentData['Service'];
        $this->is_shipped = true;
        $this->save();

        $order->pickingShipped();
    }
}
$picking = new Picking;
$picking->shipped($picking->order, $shipmentData);
但是,我认为这意味着我还需要注入订单依赖关系,而不是依赖
shipped()
方法中的
order
关系,如下所示:

class Picking extends \Eloquent {

    public function order() {
        return $this->belongsTo('Order');
    }    

    public function shipped($shipmentData) {
        $this->carrier = $shipmentData['Carrier'];
        $this->service = $shipmentData['Service'];
        $this->is_shipped = true;
        $this->save();

        $this->order->pickingShipped();
    }
}
$order->expects($this->once())->method('pickingShipped')
class Picking extends \Eloquent {

    public function order() {
        return $this->belongsTo('Order');
    }    

    public function shipped(Order $order, $shipmentData) {
        $this->carrier = $shipmentData['Carrier'];
        $this->service = $shipmentData['Service'];
        $this->is_shipped = true;
        $this->save();

        $order->pickingShipped();
    }
}
$picking = new Picking;
$picking->shipped($picking->order, $shipmentData);
然后控制器中的代码必须如下所示:

class Picking extends \Eloquent {

    public function order() {
        return $this->belongsTo('Order');
    }    

    public function shipped($shipmentData) {
        $this->carrier = $shipmentData['Carrier'];
        $this->service = $shipmentData['Service'];
        $this->is_shipped = true;
        $this->save();

        $this->order->pickingShipped();
    }
}
$order->expects($this->once())->method('pickingShipped')
class Picking extends \Eloquent {

    public function order() {
        return $this->belongsTo('Order');
    }    

    public function shipped(Order $order, $shipmentData) {
        $this->carrier = $shipmentData['Carrier'];
        $this->service = $shipmentData['Service'];
        $this->is_shipped = true;
        $this->save();

        $order->pickingShipped();
    }
}
$picking = new Picking;
$picking->shipped($picking->order, $shipmentData);
这感觉有点奇怪,但我真的不确定什么是对的


我的问题是,编写和测试此代码的正确方法是什么?测试
shipped()
方法可以很容易地在自身上设置适当的数据,但是最后调用
pickingShipped()
会怎么样?这似乎使测试更加复杂。那么代码应该重新排列吗?如果是,怎么做?或者,这是我在第二个选项中概述的模拟的常见用例吗?如果是这样的话,正如我所展示的那样注入依赖项是否正确?

我不是PHP开发人员,因此这可能归结为语言特性是一个拦截器

我认为依赖项注入方法更好,因为它调用依赖项,并允许您稍后分离持久性和行为。例如,
Picking
Picker
可能是一个更好的行为名称,而
PickingRecord
可能适合数据

在任何情况下,如果您可以在PHP中设置默认参数,那么我喜欢您使用的最后一种方法(注入),您现在可以简化为

   public function shipped($shipmentData, Order $order = $this->order) {
    $this->carrier = $shipmentData['Carrier'];
    $this->service = $shipmentData['Service'];
    $this->is_shipped = true;
    $this->save();

    $order->pickingShipped();
}
然后,这将允许您忽略生产代码中的
order
依赖项,并在测试中注入一个double或其他类型的对象作为
order
,并简单地断言该方法是在
order
对象上调用的。集成测试应该继续监控接口是否仍然在一起,即使您在单元测试中注入了双倍


这就是我在Ruby中尝试的方式

我想出了一个我觉得不错的解决方案。我现在看到这一点似乎很明显。我所做的就是设置
$picking->order
属性来返回测试的模拟订单

$order = Mockery::mock(Order::class);

$picking = new Picking;
$picking->order = $order;

$order->shouldReceive('pickingShipped')
  ->with($picking)
  ->once();

$picking->shipped($shipmentData);
现在,当
shipped()
方法调用
$this->order
时,它将获得我定义的模拟
$order
对象,并且测试工作正常


这似乎是正确的解决方案。

感谢您的反馈!这种方法的唯一问题是,我们允许将
$order
传递到方法中,而实际上不允许这样做。该方法的要点是,它必须对拣选订单调用
pickingShipped
,而不仅仅是任何订单。这意味着我们只是出于测试目的添加此参数。仅仅为了测试目的而更改方法签名感觉很奇怪。现在,该方法建议它应该用于实际不应该使用的行为。关于默认参数,是的,PHP允许您传入它们,但它们不能有像
$this->order
这样的动态值。在这种情况下,我会将默认值设置为
null
,然后在方法的开头说
if(is_null($order))$order=$this->order,这将完成同样的事情,但正如我上面所说的,这种依赖注入方法对我来说仍然不合适。