模拟 class 参数,returns 模拟
Mocking class parameter that returns a mock
我是单元测试的新手,正在尝试测试 Laravel 5.1 和 Mockery 中的控制器方法。
我正在尝试测试我编写的 registerEmail
方法,如下所示:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Response;
use Mailchimp;
use Validator;
/**
* Class ApiController
* @package App\Http\Controllers
*/
class ApiController extends Controller
{
protected $mailchimpListId = null;
protected $mailchimp = null;
public function __construct(Mailchimp $mailchimp)
{
$this->mailchimp = $mailchimp;
$this->mailchimpListId = env('MAILCHIMP_LIST_ID');
}
/**
* @param Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function registerEmail(Request $request)
{
$this->validate($request, [
'email' => 'required|email',
]);
$email = $request->get('email');
try {
$subscribed = $this->mailchimp->lists->subscribe($this->mailchimpListId, [ 'email' => $email ]);
//var_dump($subscribed);
} catch (\Mailchimp_List_AlreadySubscribed $e) {
return Response::json([ 'mailchimpListAlreadySubscribed' => $e->getMessage() ], 422);
} catch (\Mailchimp_Error $e) {
return Response::json([ 'mailchimpError' => $e->getMessage() ], 422);
}
return Response::json([ 'success' => true ]);
}
}
我正在尝试模拟 Mailchimp 对象以在这种情况下工作。
到目前为止,我的测试如下所示:
<?php
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class HomeRouteTest extends TestCase
{
use WithoutMiddleware;
public function testMailchimpReturnsDuplicate() {
$listMock = Mockery::mock('Mailchimp_Lists')
->shouldReceive('subscribe')
->once()
->andThrow(\Mailchimp_List_AlreadySubscribed::class);
$mailchimp = Mockery::mock('Mailchimp')->lists = $listMock;
$this->post('/api/register-email', ['email'=>'duplicate@email.com'])->assertJson(
'{"mailchimpListAlreadySubscribed": "duplicate@email.com is already subscribed to the list."}'
);
}
}
我让 phpUnit 返回一个失败的测试。
HomeRouteTest::testMailchimpReturnsDuplicate
Mockery\Exception\InvalidCountException: Method subscribe() from Mockery_0_Mailchimp_Lists should be called exactly 1 times but called 0 times.
此外,如果我断言状态代码为 422,phpUnit 会报告它正在接收状态代码 200。
当我手动测试它时它工作正常,但我想我忽略了一些相当容易的事情。
Mockery 期望传递给控制器的 class 是一个模拟对象,正如您在他们的 docs:
中看到的那样
class Temperature
{
public function __construct($service)
{
$this->_service = $service;
}
}
单元测试
$service = m::mock('service');
$service->shouldReceive('readTemp')->times(3)->andReturn(10, 12, 14);
$temperature = new Temperature($service);
在 laravel IoC 中它会自动加载 classes 并注入它们,但由于它不会自动加载 Mailchimp_Lists
class 它不会是模拟对象。 Mailchimp 需要 class 在其主要 class require_once 'Mailchimp/Lists.php';
之上
然后 Mailchimp 会在构造函数中自动加载 class
$this->lists = new Mailchimp_Lists($this);
我不认为你能够很容易地开箱即用地模拟 class。由于无法将模拟对象传递给 Mailchimp class 并让它替换真实 Mailchimp_Lists
的实例
我看到您在调用控制器之前试图用新的 Mock 覆盖 lists 成员变量。您确定列表对象正在被您模拟的对象替换吗?尝试在控制器加载时查看 classes 是什么,看看它是否真的被覆盖了。
我自己设法解决了。我最终将订阅移到了一个单独的作业中 class,并且能够测试重新定义测试文件中的 Mailchimp class。
class Mailchimp {
public $lists;
public function __construct($lists) {
$this->lists = $lists;
}
}
class Mailchimp_List_AlreadySubscribed extends Exception {}
还有一个测试
public function testSubscribeToMailchimp() {
// create job
$subscriber = factory(App\Models\Subscriber::class)->create();
$job = new App\Jobs\SubscribeToList($subscriber);
// set up Mailchimp mock
$lists = Mockery::mock()
->shouldReceive('subscribe')
->once()
->andReturn(true)
->getMock();
$mailchimp = new Mailchimp($lists);
// handle job
$job->handle($mailchimp);
// subscriber should be marked subscribed
$this->assertTrue($subscriber->subscribed);
}
我是单元测试的新手,正在尝试测试 Laravel 5.1 和 Mockery 中的控制器方法。
我正在尝试测试我编写的 registerEmail
方法,如下所示:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Response;
use Mailchimp;
use Validator;
/**
* Class ApiController
* @package App\Http\Controllers
*/
class ApiController extends Controller
{
protected $mailchimpListId = null;
protected $mailchimp = null;
public function __construct(Mailchimp $mailchimp)
{
$this->mailchimp = $mailchimp;
$this->mailchimpListId = env('MAILCHIMP_LIST_ID');
}
/**
* @param Request $request
* @return \Illuminate\Http\JsonResponse
*/
public function registerEmail(Request $request)
{
$this->validate($request, [
'email' => 'required|email',
]);
$email = $request->get('email');
try {
$subscribed = $this->mailchimp->lists->subscribe($this->mailchimpListId, [ 'email' => $email ]);
//var_dump($subscribed);
} catch (\Mailchimp_List_AlreadySubscribed $e) {
return Response::json([ 'mailchimpListAlreadySubscribed' => $e->getMessage() ], 422);
} catch (\Mailchimp_Error $e) {
return Response::json([ 'mailchimpError' => $e->getMessage() ], 422);
}
return Response::json([ 'success' => true ]);
}
}
我正在尝试模拟 Mailchimp 对象以在这种情况下工作。 到目前为止,我的测试如下所示:
<?php
use Illuminate\Foundation\Testing\WithoutMiddleware;
use Illuminate\Foundation\Testing\DatabaseMigrations;
use Illuminate\Foundation\Testing\DatabaseTransactions;
class HomeRouteTest extends TestCase
{
use WithoutMiddleware;
public function testMailchimpReturnsDuplicate() {
$listMock = Mockery::mock('Mailchimp_Lists')
->shouldReceive('subscribe')
->once()
->andThrow(\Mailchimp_List_AlreadySubscribed::class);
$mailchimp = Mockery::mock('Mailchimp')->lists = $listMock;
$this->post('/api/register-email', ['email'=>'duplicate@email.com'])->assertJson(
'{"mailchimpListAlreadySubscribed": "duplicate@email.com is already subscribed to the list."}'
);
}
}
我让 phpUnit 返回一个失败的测试。
HomeRouteTest::testMailchimpReturnsDuplicate Mockery\Exception\InvalidCountException: Method subscribe() from Mockery_0_Mailchimp_Lists should be called exactly 1 times but called 0 times.
此外,如果我断言状态代码为 422,phpUnit 会报告它正在接收状态代码 200。
当我手动测试它时它工作正常,但我想我忽略了一些相当容易的事情。
Mockery 期望传递给控制器的 class 是一个模拟对象,正如您在他们的 docs:
中看到的那样class Temperature
{
public function __construct($service)
{
$this->_service = $service;
}
}
单元测试
$service = m::mock('service');
$service->shouldReceive('readTemp')->times(3)->andReturn(10, 12, 14);
$temperature = new Temperature($service);
在 laravel IoC 中它会自动加载 classes 并注入它们,但由于它不会自动加载 Mailchimp_Lists
class 它不会是模拟对象。 Mailchimp 需要 class 在其主要 class require_once 'Mailchimp/Lists.php';
然后 Mailchimp 会在构造函数中自动加载 class
$this->lists = new Mailchimp_Lists($this);
我不认为你能够很容易地开箱即用地模拟 class。由于无法将模拟对象传递给 Mailchimp class 并让它替换真实 Mailchimp_Lists
我看到您在调用控制器之前试图用新的 Mock 覆盖 lists 成员变量。您确定列表对象正在被您模拟的对象替换吗?尝试在控制器加载时查看 classes 是什么,看看它是否真的被覆盖了。
我自己设法解决了。我最终将订阅移到了一个单独的作业中 class,并且能够测试重新定义测试文件中的 Mailchimp class。
class Mailchimp {
public $lists;
public function __construct($lists) {
$this->lists = $lists;
}
}
class Mailchimp_List_AlreadySubscribed extends Exception {}
还有一个测试
public function testSubscribeToMailchimp() {
// create job
$subscriber = factory(App\Models\Subscriber::class)->create();
$job = new App\Jobs\SubscribeToList($subscriber);
// set up Mailchimp mock
$lists = Mockery::mock()
->shouldReceive('subscribe')
->once()
->andReturn(true)
->getMock();
$mailchimp = new Mailchimp($lists);
// handle job
$job->handle($mailchimp);
// subscriber should be marked subscribed
$this->assertTrue($subscriber->subscribed);
}