Is it possible to mock the
EntityRepository::findOneBy{$field}($value)
function?
Using:
->getMock('EntityRepository')
->expects($this->any())
->method('findOneByField')
resolves always in null, as findOneByField isn't a real function but gets mapped by __call(). At least I think that that is the problem..
You can mock the __call method. Will give a simple example:
Class:
class A {
public function __call($fname, $args) {
if($fname === 'test') {
return 'test';
}
}
}
Test:
class ATest extends PHPUnit_Framework_TestCase
{
public function testA() {:
$mock = $this->getMock('A');
$mock->expects($this->any())
->method('__call')
->with('test')
->will($this->returnValue('test'));
var_dump($mock->test());
}
}
You can do the same with the EntityRepository. I just hadn't one by the hand for testing.
Related
Hello lets say I want to test the function run from Class A and I'm using Mockery to mock external dependencies:
class A {
protected myB;
public function __construct(B $param) {
$this->myB = $param;
}
protected function doStuff() {
return "done";
}
public function run() {
$this->doStuff();
$this->myB->doOtherStuff();
return "finished";
}
}
class B {
public function doOtherStuff() {
return "done";
}
}
So I wrote the test like this:
public function testRun() {
$mockB = Mockery::mock('overload:B');
$mockB->shouldReceive('doOtherStuff')
->andReturn("not done");
$mockA = Mockery::mock(A::class)->makePartial()->shouldAllowMockingProtectedMethods();
$mockA->shouldReceive('doStuff')->andReturns("done");
$mockA->run();
}
This throws me an exception like this:
Error: Call to a member function doStuff() on null
I tried diffrent variations of mocking the internal dependency B which is getting called in the run function but I always endend up in an exception.
What am I doing wrong here?
Don't mock the thing you are testing. Inject the mocked B into A.
public function testRun()
{
// Arrange
$mockB = Mockery::mock(B::class);
$a = new A($mockB);
// Assert
$mockB->shouldReceive('doOtherStuff')
->once()
->andReturn("not done");
// Act
$a->run();
}
If you want to monkey patch A, you can still pass the mocked B in (more details: constructor arguments in mockery):
public function testRun()
{
// Arrange
$mockB = Mockery::mock(B::class);
$a = Mockery::mock(A::class, [$mockB])
->makePartial()
->shouldAllowMockingProtectedMethods();
$a->shouldReceive('doStuff')
->andReturns('mocked done');
// Assert
$mockB->shouldReceive('doOtherStuff')
->once()
->andReturn('not done');
// Act
$a->run();
}
I have a controller class with a method something() which makes calls to two different methods of the same class and merge the result of two calls.
class Controller{
...
public UDC doSomething(){
CompletableFuture<UDC> feature1 = CompletableFuture.supplyAsync(()-> {this.doOther()}).exceptionally(ex -> {return new SomeException();});
CompletableFuture<UDC> feature2 = CompletableFuture.supplyAsync(()-> {this.doSomeOther()}).exceptionally(ex -> {return new SomeException();});
...
return feature1.combine(feature2).get();
}
...
}
I don't think you should use Mockito to mock CompletableFuture here, any of them...
In the test, treat the Controller's doSomething functionality as a black box that given some input returns UDC.
Now, it's possible that doOther and/or doSomeOther call some external code that should be mocked. In this case the Controller looks probably something like this:
class Controller {
private final SomeExternalDependency dependency1;
public Controller(SomeExternalDependency dependency1) {
this.dependency1 = dependency1;
}
private UDC doOther() {
...
dependency1.foo();
...
}
private UDC toSomeOther() {
...
dependency1.bar();
...
}
}
In this case in the test you can mock out the dependency1 with mockito as usual:
class MyTest {
#Test
public void doSomething() {
SomeExternalDependency dep = Mockito.mock(SomeExternalDependency.class);
// specify the expectations
Controller controller = new Controller(dep);
controller.doSomething();
}
}
In Laravel 5.2, I want to unit test my Eloquent User Repository.
class EloquentUserRepository implements UserRepositoryInterface
{
private $user;
public function __construct(User $user)
{
$this->user = $user;
}
public function oneUser($id)
{
return $this->user->oneUser($id);
}
}
My test looks like below, with mocking the interface:
class EloquentUserRepositoryTest extends TestCase
{
public function setUp()
{
$this->user = factory(User::class, 1)->create(['name' => 'foo']);
}
/** #test */
public function it_fetch_an_user()
{
$mock = Mockery::mock('App\Repositories\Interfaces\UserRepositoryInterface')
->shouldReceive('oneUser')
->once()
->with($this->user->id)
->andReturn('foo');
App::instance(App\Repositories\EloquentUserRepository::class, $mock);
$userRepository = App::make(App\Repositories\EloquentUserRepository::class);
$this->assertEquals('foo', $userRepository->oneUser($this->user->id)->name);
}
public function tearDown()
{
Mockery::close();
}
}
I get this error:
ErrorException: call_user_func_array() expects parameter 1 to be a valid callback, class 'Mockery\Expectation' does not have a method 'oneUser'
I expect a simulated object that has the method oneUser, but it returns Mockery\Expectation. What do I wrong?
When a new instance of EloquentUserRepository is made, a new user model is created. When you then call the oneUser method for the EloquentUserRepository class a method with the same name is called but on the user model. Therefore it's the user model you need to mock, not the UserRepositoryInterface.
You need to create a new instance of the EloquentUserRepository and send in the user model mock as an argument when it's created as shown below:
class EloquentUserRepositoryTest extends TestCase
{
protected $userMock;
public function setUp()
{
parent::setUp();
$this->userMock = Mockery::mock('User');
$this->userMock->id = 1;
}
/** #test */
public function it_fetch_an_user()
{
$this->userMock->shouldReceive('oneUser')->with($this->userMock->id)->andReturn('foo');
$userRepository = App::make(App\Repositories\EloquentUserRepository::class, array($this->userMock));
$this->assertEquals('foo', $userRepository->oneUser($this->userMock->id));
}
public function tearDown()
{
Mockery::close();
}
}
I have a problem on unit testing my project.
This is my code:
namespace Way\Storage\HalisahaAccount;
# app/lib/Way/Storage/HalisahaAccount/HalisahaAccountRepositoryInterface.php
interface HalisahaAccountRepositoryInterface {
public function all();
public function find($id);
public function create($input);
}
And the Eloquent repository
namespace Way\Storage\HalisahaAccount;
# app/lib/Way/Storage/HalisahaAccount/EloquentHalisahaAccountRepository.php
use HalisahaAccount;
class EloquentHalisahaAccountRepository implements HalisahaAccountRepositoryInterface {
public function all()
{
return HalisahaAccount::all();
}
public function find($id)
{
return HalisahaAccount::find($id);
}
public function create($input)
{
return HalisahaAccount::create($input);
}
}
And this is my model: HalisahaAccount
class HalisahaAccount extends Eloquent {
/**
* shouldReceive for test
*/
public static function shouldReceive()
{
$class = get_called_class();
$repo = "Way\\Storage\\{$class}\\{$class}RepositoryInterface";
$mock = Mockery::mock($repo);
App::instance($repo, $mock);
return call_user_func_array([$mock, 'shouldReceive'], func_get_args());
}
}
Controller
class HalisahalarController extends BaseController {
protected $halisahaAccount;
public function __construct (HalisahaAccount $halisahaAccount) {
$this->halisahaAccount = $halisahaAccount;
}
public function getIndex(){
$halisahalar = $this->halisahaAccount->all();
return View::make('index',array('halisahalar' => $halisahalar));
}
}
And my test
class HalisahalarControllerTest extends TestCase {
public function tearDown(){
Mockery::close();
}
/**
* halısahaların listelendiği sayfanın testi
*/
public function testGetIndex(){
HalisahaAccount::shouldReceive('all')->once();
$this->client->request('GET', '/halisahalar');
$this->assertViewHas('halisahalar');
}
}
I am running the phpunit test, but getting the this error:
1) HalisahalarControllerTest::testGetIndex
Mockery\Exception\InvalidCountException: Method all() from Mockery_0_Way_Storage_HalisahaAccount_HalisahaAccountRepositoryInterface should be called
exactly 1 times but called 0 times.
Why the mockery dont call my all() method?
Maybe I am doing this wrong.
I'd like to test the beforeSave method of a model (Antibody). A part of this method calls a method on an associated model (Species). I'd like to mock the Species model but don't find how.
Is it possible or am I doing something that goes against the MVC pattern and thus trying to do something that I shouldn't?
class Antibody extends AppModel {
public function beforeSave() {
// some processing ...
// retreive species_id based on the input
$this->data['Antibody']['species_id']
= isset($this->data['Species']['name'])
? $this->Species->getIdByName($this->data['Species']['name'])
: null;
return true;
}
}
Assuming your Species model in created by cake due to relations, you can simply do something like this:
public function setUp()
{
parent::setUp();
$this->Antibody = ClassRegistry::init('Antibody');
$this->Antibody->Species = $this->getMock('Species');
// now you can set your expectations here
$this->Antibody->Species->expects($this->any())
->method('getIdByName')
->will($this->returnValue(/*your value here*/));
}
public function testBeforeFilter()
{
// or here
$this->Antibody->Species->expects($this->once())
->method('getIdByName')
->will($this->returnValue(/*your value here*/));
}
Well, it depends on the way your 'Species' object is injected.
Is it injected via the constructor ? Via a setter ? Is it inherited ?
Here is an example with a constructor injected object :
class Foo
{
/** #var Bar */
protected $bar;
public function __construct($bar)
{
$this->bar = $bar;
}
public function foo() {
if ($this->bar->isOk()) {
return true;
} else {
return false;
}
}
}
Then your test would be something like this:
public function test_foo()
{
$barStub = $this->getMock('Overblog\CommonBundle\TestUtils\Bar');
$barStub->expects($this->once())
->method('isOk')
->will($this->returnValue(false));
$foo = new Foo($barStub);
$this->assertFalse($foo->foo());
}
The process is quite the same with setter injected objects :
public function test_foo()
{
$barStub = $this->getMock('Overblog\CommonBundle\TestUtils\Bar');
$barStub->expects($this->once())
->method('isOk')
->will($this->returnValue(false));
$foo = new Foo();
$foo->setBar($barStub);
$this->assertFalse($foo->foo());
}