我想在PHPUnit测试中使用模拟对象(Mockery).模拟对象需要设置一些公共方法和一些公共属性.该课程是Laravel Eloquent模型.我试过这个:
$mock = Mockery::mock('User');
$mock->shouldReceive('hasRole')->once()->andReturn(true); //works fine
$mock->roles = 2; //how to do this? currently returns an error
$this->assertTrue(someTest($mock));
Run Code Online (Sandbox Code Playgroud)
...但是设置公共属性会返回以下错误:
BadMethodCallException:方法Mockery_0_User :: setAttribute()在此模拟对象上不存在
模拟一个简单的类时不会返回此错误,但在我尝试模拟Eloquent模型时会返回此错误.我究竟做错了什么?
我正在锁定一种模拟对象并填充其属性的方法.以下是使用另一个对象的属性的方法示例:
class MyClass {
private $_object;
public function methodUnderTest($object) {
$this->_object = $object;
return $this->_object->property
}
}
Run Code Online (Sandbox Code Playgroud)
要单元测试这个方法我应该$object用getMockBuilder()方法创建一个模拟PHPUnit.但我找不到一种方法来模拟属性$object,只是方法.
我已经使用Laravel一段时间了,我已经阅读了很多关于依赖注入的可测试代码.在谈到Facades和Mocked Objects时,我已经陷入了困惑.我看到两种模式:
class Post extends Eloquent {
protected $guarded = array();
public static $rules = array();
}
Run Code Online (Sandbox Code Playgroud)
这是我的帖子模型.我可以跑来Post::all();从我的博客上获取所有帖子.现在我想将它合并到我的控制器中.
我的第一直觉是将Post模型作为依赖注入:
class HomeController extends BaseController {
public function __construct(Post $post)
{
$this->post = $post;
}
public function index()
{
$posts = $this->posts->all();
return View::make( 'posts' , compact( $posts );
}
}
Run Code Online (Sandbox Code Playgroud)
我的单元测试看起来像这样:
<?php
use \Mockery;
class HomeControllerTest extends TestCase {
public function tearDown()
{
Mockery::close();
parent::tearDown();
}
public function testIndex()
{
$post_collection = new StdClass();
$post = …Run Code Online (Sandbox Code Playgroud) $client = Mockery::mock();
$client->shouldReceive('send')->andThrow($error)->andReturn(true);
Run Code Online (Sandbox Code Playgroud)
不幸的是,它只返回true但不首先抛出异常.如何在第一次调用时抛出异常,然后在方法的第二次调用时返回值?
编辑:
如果我手动编辑Mockery\Expectation.php和设置,这是有效的$_throw
= true.
$client->shouldReceive('send')->twice()->andReturn($error, true);
Run Code Online (Sandbox Code Playgroud) 是否可以使用PHP Mockery模拟受保护的属性?
我得到了一个带有方法的类,我将其称为"a",它在从同一个类的受保护属性中检索的数组上做了一些魔术.
受保护的属性由另一个方法填充b,在同一个类中.
我想a通过模拟受保护的属性来测试方法,所以我不必b首先使用类方法.
这可能吗?如果没有,我应该重构我的代码吗?或者还有其他方法(考虑最佳实践).
我试图让Mockery声明一个给定的方法被调用至少一次.
我的测试类是:
use \Mockery as m;
class MyTest extends \PHPUnit_Framework_TestCase
{
public function testSetUriIsCalled()
{
$uri = 'http://localhost';
$httpClient = m::mock('Zend\Http\Client');
$httpClient->shouldReceive('setUri')->with($uri)->atLeast()->once();
}
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,有一个测试(希望)创建了一个期望setUri将被调用的测试.由于没有涉及任何其他代码,我无法想象它可以调用,但我的测试通过.有谁能解释为什么?
我无法弄清楚为什么我在这次测试中遇到这个错误.我的测试似乎与其余代码完全匹配.我在俯瞰什么?
在我的测试中,我有:
$passwordBroker = m::mock('Illuminate\Auth\Reminders\PasswordBroker');
$passwordBroker->shouldReceive('reset')
->once()
->with(
$this->resetAttributes,
m::on(function (\Closure $closure) {
$this->entity
->shouldReceive('setAttribute')
->once()
->with('password', $this->resetAttributes['password']);
$this->entity
->shouldReceive('getAttributes')
->once()
->andReturn($this->resetAttributes);
$closure($this->entity, $this->resetAttributes['password']);
})
);
Run Code Online (Sandbox Code Playgroud)
错误:
Mockery\Exception\NoMatchingExpectationException: No matching handler found for Mockery_4_Illuminate_Auth_Reminders_PasswordBroker::reset(array('email'=>'test@email.com','password'=>'myTestPassword','password_confirmation'=>'myTestPassword',), Closure). Either the method was unexpected or its arguments matched no expected argument list for this method
Objects: (array (
'Closure' =>
array (
'class' => 'Closure',
'properties' =>
array (
),
'getters' =>
array (
),
),
))
Run Code Online (Sandbox Code Playgroud)
我缺乏理解的部分原因可能与我不确定Objects: array(....)错误底部出现的事实有关.
我试图模拟一个对象,该对象获得两个相同函数但具有不同参数的调用.为多个调用返回不同的返回值非常简单但我无法在任何地方找到如何使用参数验证来执行此操作.
我试过了:
$this->eventDispatcher
->shouldReceive('dispatch')
->twice()
->with(Events::SELECT,\Mockery::type('\Not\Really\A\Namespace\Event'))
->with(Events::ACTIVITY,\Mockery::type('\Not\Really\A\Namespace\Event');
Run Code Online (Sandbox Code Playgroud)
和
$this->eventDispatcher
->shouldReceive('dispatch')
->twice()
->with(
[Events::SELECT,\Mockery::type('\Not\Really\A\Namespace\Event')],
[Events::ACTIVITY,\Mockery::type('\Not\Really\A\Namespace\Event')]
);
Run Code Online (Sandbox Code Playgroud)
但他们不工作.
从输出PHPUnit给我看起来我似乎得到一个数组?
我使用laravel(4.1)框架,我读了"Laravel-testing-decoding",这是Jeffrey Wey的电子书.
我想测试我的模态用户和我的方法 setPasswordAttribute($password)
我的单元测试:
<?php
class UserTest extends TestCase {
public function testHashesPasswordWhenSet(){
Hash::shouldReceive('make')->once()->andReturn('hashed');
$user = new User;
$user->password = 'food';
$this->assertEquals('hashed', $user->password);
}
}
Run Code Online (Sandbox Code Playgroud)
但是当我启动CLI时:phpunit它返回一个错误:Fatal error: Class 'Mockery' not found
完全错误:
Fatal error: Class 'Mockery' not found in /Applications/MAMP/htdocs/ptf/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php on line 84
Call Stack:
0.0021 236384 1. {main}() /Applications/MAMP/htdocs/ptf/vendor/phpunit/phpunit/composer/bin/phpunit:0
0.0294 1425104 2. PHPUnit_TextUI_Command::main() /Applications/MAMP/htdocs/ptf/vendor/phpunit/phpunit/composer/bin/phpunit:63
0.0294 1425336 3. PHPUnit_TextUI_Command->run() /Applications/MAMP/htdocs/ptf/vendor/phpunit/phpunit/PHPUnit/TextUI/Command.php:129
0.0692 3626416 4. PHPUnit_TextUI_TestRunner->doRun() /Applications/MAMP/htdocs/ptf/vendor/phpunit/phpunit/PHPUnit/TextUI/Command.php:176
0.0741 3944720 5. PHPUnit_Framework_TestSuite->run() /Applications/MAMP/htdocs/ptf/vendor/phpunit/phpunit/PHPUnit/TextUI/TestRunner.php:349
0.0741 3946368 6. PHPUnit_Framework_TestSuite->run() /Applications/MAMP/htdocs/ptf/vendor/phpunit/phpunit/PHPUnit/Framework/TestSuite.php:705
0.0742 …Run Code Online (Sandbox Code Playgroud) 我在我的代码中有这样一行:
ModelName::create($data);
Run Code Online (Sandbox Code Playgroud)
其中ModelName只是一个Eloquent模型.有没有办法在单元测试中模拟这个调用?我尝试过:
$client_mock = \Mockery::mock('Eloquent','App\Models\ModelName');
$client_mock->shouldReceive('create')
->with($data)->andReturns($returnValue);
Run Code Online (Sandbox Code Playgroud)
但它不起作用.