EzDevInfo.com

mockery

Simplifying the use of mocks with Node.js

PHP Unit Testing and Mocking with Mockery

This could be a misunderstanding from my side about mocking, and would really appreciate an explanation on how is mocking an inexistent or existent class is a good thing ?

Example Scenario: Say we have one class dependent on the output of the second class, and we change in the output format or whatever, wouldn't this keep our tests succeeding although they're outdated in the first class ?


Source: (StackOverflow)

Yii2 ActiveRecord mocking with Mockery

I'm running phpunit with mockery (without DB/fixtures), but I have a trouble with mocking a model.

$customer = Mockery::mock(CustomerModel::class);
echo $customer->id;

Produces error:

BadMethodCallException: Method Mockery_1_models_Customer::hasAttribute() does not exist on this mock object

Then I tried:

$customer->shouldReceive('hasAttribute')->andReturn(true);

But again, I run in to:

Fatal error: Call to a member function getDb() on a non-object in ..\yiisoft\yii2\db\ActiveRecord.php on line 135

Any suggestions?


Source: (StackOverflow)

Advertisements

Laravel 4.1 - Testing an Artisan command with Phpunit and Mockery

I'm writing my first Artisan command in Laravel 4.1 and wanted to get some ideas on how to test it. My command does one thing (for now). It basically deletes table entries (Notes) from a DB that are a specified amount of days old.


Command Example:

OneTimeNote:delete --days=25

The command works with flying colors. But I've written the command first for learning purposes and now I desire to follow it with a test. I'm using PHPUnit and Mockery.


Command Code: http://pastebin.com/index/dZrxpt8x

As you can see, I'm injecting my Note implementation (for abstraction) and then I'm executing one of it's methods 'deleteNotesOlderThan(int $days)'. Like I said, this all works fine and dandy. My issue starts when I'm trying to test the thing.


Command Test: http://pastebin.com/6UwxGvcN

If you look at the code, you can see where I'm stuck at. How do I Mock my Note method and generate a Command Test? Also what sort of things should I be testing with this particular command?

Thank you in advance


Source: (StackOverflow)

Laravel 5 mock PasswordBroker

From the boilerplate PasswordController::postEmail() I'm trying to mock (using Mockery) this part:

// $this->password is an instance of PasswordBroker
$response = $this->passwords->sendResetLink($request->only('email'), function($m)
    {
        $m->subject($this->getEmailSubject());
    });

In my test case, I'm calling ->shouldReceive('sendResetLink')->with($postData, ???)

Since this is a closure, I'm sure I have to pass a closure, and also mock the $m->subject($this->getEmailSubject()); but I am blank on this one, as I'm relatively new to TDD.

Can I get some directions please?


Source: (StackOverflow)

Laravel Testing - Throwing exception with Mockery

I'm very new to Laravel and unit testing in general. I'm trying to write some tests for my AccountController and I've run into a road block.

I'm using Sentry to handle users and groups in the site. I'm trying to test that my controller is handling exceptions thrown by Sentry properly. So my controller method that handles the login POST looks like this:

public function postLogin(){

    $credentials = array(
        'email' => Input::get('email'),
        'password' => Input::get('password')
    );

    try{
        $user = $this->authRepo->authenticate($credentials, true);
        return Redirect::route('get_posts');
    }
    catch (Exception $e){
        $message = $this->getLoginErrorMessage($e);
        return View::make('login', array('errorMsg' => $message));
    }
}

authRepository is just a repository that uses Sentry to handle authentication. Now I want to test that when an email address is not specified a LoginRequiredException is thrown and the user sees the error message. Here is my test:

public function testPostLoginNoEmailSpecified(){

    $args = array(
        'email' => 'test@test.com'
    );

    $this->authMock
        ->shouldReceive('authenticate')
        ->once()
        ->andThrow(new Cartalyst\Sentry\Users\LoginRequiredException);

    $this->action('POST', 'MyApp\Controllers\AccountController@postLogin', $args);

    $this->assertViewHas('errorMsg', 'Please enter your email address.');
}

However, the test is not passing. For some reason all it spits out is:

There was 1 error:

1) AccountControllerTest::testPostLoginNoEmailSpecified
Cartalyst\Sentry\Users\LoginRequiredException: 

Am I using the andThrow() method incorrectly? If anyone can shed any light on what is going on it would be much appreciated.

Thanks in advance!


Source: (StackOverflow)

Asserting a changed state on a mocked object

I would like to unit test a function that takes a certain object as input, processes it and when it finished, the state of that object should have been changed to a certain value.

As I want to do "real" unit testing (as I understand it), I only want to use the class that is providing the processing function, and mock all other classes used. To fulfill this requirement I need to mock the object that is being processed; but when it is only a mock, it has no real state anymore that could be changed.

Example pseudocode:

object = createMock('SomeClassName');
object.whenReceives('getState').shouldReturn(0);

Processor.process(object);
assertEquals(expected = 1, actual = object.getState());

The problem is that I need to mock the "getState" method to prepare the starting state for the test, and so afterwards I cannot use the real method anymore. Do you know how can I achieve this, or how I should change the design of the test?

PS: I am actually using PHPUnit and Mockery.

Thank you for any advice.


Source: (StackOverflow)

How to ensure that a method exists in the real object when mocked?

I would like my test to fail if I mock an interface using Mockery and use a shouldReceive with a non-existing method. Looking around didn't help.

For instance :

With an interface :

interface AInterface {
    public function foo();
    public function bar();
}

And a test case :

function testWhatever{
    Mockery::mock('AInterface')->shouldReceive('bar');
    $this->assertTrue(true);
}

The test will pass.

Now, refactoring time, bar method is not needed in one place (let's say it's needed on several places) and is suppressed from the interface definition but the test will still pass. I would like it to fail.

Is it possible to do such a thing using mockery (and to be able to do the same thing with a class instead of an interface) ? Or does a workaround exist with some other tool or a testing methodology ?

Not sur if this can be understood as is, will try to make a clearer description of the issue if needed.


Source: (StackOverflow)

Mockery object argument validation issue

Consider the example classes (apologies for it being so convoluted, but it's as slim as possible):

class RecordLookup
{
    private $records = [
        13 => 'foo',
        42 => 'bar',
    ];

    function __construct($id)
    {
        $this->record = $this->records[$id];
    }

    public function getRecord()
    {
        return $this->record;
    }
}

class RecordPage
{
    public function run(RecordLookup $id)
    {
        return "Record is " . $id->getRecord();
    }
}

class App
{
    function __construct(RecordPage $page, $id)
    {
        $this->page = $page;
        $this->record_lookup = new RecordLookup($id);
    }

    public function runPage()
    {
        return $this->page->run($this->record_lookup);
    }
}

In which I want to test App whilst mocking RecordPage:

class AppTest extends \PHPUnit_Framework_TestCase
{
    function testAppRunPage()
    {
        $mock_page = \Mockery::mock('RecordPage');

        $mock_page
            ->shouldReceive('run')
            ->with(new RecordLookup(42))
            ->andReturn('bar');

        $app = new App($mock_page, 42);

        $this->assertEquals('Record is bar', $app->runPage());
    }
}

Note: the expected object argument ->with(new RecordLookup(42)).

I would expect this to pass however Mockery returns throws No matching handler found for Mockery_0_RecordPage::run(object(RecordLookup)). Either the method was unexpected or its arguments matched no expected argument list for this method.

I'm assuming this is because a strict comparison is used for the arguments expected through with() and new RecordLookup(42) === new RecordLookup(42) evaluates as false. Note new RecordLookup(42) == new RecordLookup(42) evaluates as true so if there was someway of relaxing the comparison it would fix my problem.

Is there a proper way to handle expected instance arguments in Mockery? Maybe I'm using it incorrectly?


Source: (StackOverflow)

Mocking Illuminate\Database\Eloquent\Model

I need to mock Laravel's Eloquent\Model with Mockery and it is kind of tricky because it uses static methods.

I solved this issue with the following code but I wonder if there is a better/smarter way to do this.

<?php

use Ekrembk\Repositories\EloquentPostRepository;

class EloquentPostRepositoryTest extends TestCase {
    public function __construct()
    {
        $this->mockEloquent = Mockery::mock('alias:Ekrembk\Post');
    }

    public function tearDown()
    {
        Mockery::close();
    }

    public function testTumuMethoduEloquenttenAldigiCollectioniDonduruyor()
    {
        $eloquentReturn = 'fake return';
        $this->mockEloquent->shouldReceive('all')
                     ->once()
                     ->andReturn($eloquentDongu);
        $repo = new EloquentPostRepository($this->mockEloquent);

        $allPosts = $repo->all();
        $this->assertEquals($eloquentReturn, $allPosts);
    }
}

Source: (StackOverflow)

Instance mocking and implicit constructors

I am trying to use TDD on a class that manages database connections. However

  • I am often developing away from the network where the databases are available
  • I want to just test the classes not mess about with real connections, even to SQLite :memory:
  • I may want to test connections in a platform-independent manner (eg. exchanging PDO objects for MySQLi objects etc). Especially as the databases are not all MySQL, some are SQLServer.

Essentially I want to do this:

class ConnectionManager {
    ...
    public function getConnection($name) {
        $params = $this->lookup($name);
        return new \PDO($params['spec'], $params['username'], $params['password']);
    }
}

And in my test runner:

class ConnectionManagerTest extends \PHPUnit_Framework_TestCase {
    public function testGetConnection() {
        $cxn = new ConnectionManager(); 
        $this->assertNotNull($cxn->getConnection('test')); // or whatever
    }
}

Somehow I would like to use a mock of the PDO class. Is my only option to add an explicit parameter to the test class constructor or one of its methods? I've tried using 'Instance mocking' as per Mockery documentation, but as I'm using autoloading that results in 'fatal error cannot redeclare class' (duh).

I'd prefer not to pollute the contracts with code purely used in testing, but is that my only option?

Thanks for your help


Source: (StackOverflow)

How can I test a function that uses DateTime to get the current time?

Most of the answers I have seen on StackOverflow are without using the DateTime object, and are instead using the date() function. This makes them very dirty solutions (overriding date(), mocking a protected function of the subject under test, etc).

Is there a way to mock DateTime, effectively mocking the current date/time?

As an example, here is the code I'd like to test:

public function __construct(UserInterface $user, EntityManager $manager)
{
    $this->user = $user;
    $this->manager = $manager;
}

public function create(Tunnel $tunnel, $chain, $response)
{
    $history = new CommandHistory();

    $history->setTunnel($tunnel)
        ->setCommand($chain)
        ->setResponse($response)
        ->setUser($this->user)
    ;

    $this->manager->persist($history);
    $this->manager->flush();
}

Here is where I set the date and time in my CommandHistory class:

class CommandHistory
{
    // Property definitions...

    public function __construct()
    {
        $this->time = new \DateTime();
    }
}

And here is my unit test:

public function testCreate()
{
    $user = new User();
    $manager = $this->mockManagerWithUser($user);

    $tunnel = $this->tunnel;
    $chain = 'Commands`Chain';
    $response = 'This is the response!';

    $creator = new CommandHistoryCreator($user, $manager);
    $creator->create($tunnel, $chain, $response);
}

protected function mockManagerWithUser(UserInterface $user)
{
    $manager = \Mockery::mock('Doctrine\ORM\EntityManager');

    $manager->shouldReceive('persist')->once()->with(\Mockery::on(function(CommandHistory $argument) use ($user) {
        return
            $argument->getCommand() === 'Commands`Chain'
            && $argument->getResponse() === 'This is the response!'
            && $argument->getTunnel() === $this->tunnel
            && $argument->getUser() === $user
        ;
    }));
    $manager->shouldReceive('flush')->once()->withNoArgs();

    return $manager;
}

As you can see, I've created a rather long-winded closure only to exclude the comparison of the field that contains the current time, and I feel like this is hurting the readability of my test.

Also, to preserve ease of use for people who are using this class, I don't want to have to make them pass in the current time to the create() function. I believe adding strange behavior to my classes only to make them testable means I'm doing something wrong.


Source: (StackOverflow)

Laravel Queue::shouldReceive()

I have the following in one of my routes

$rules = array(
    'name' => 'Required',
    'subject' => 'Required',
    'message' => 'Required',
    'email' => 'Required|Email',
    'recaptcha_response_field' => 'required|recaptcha'
);

$validator = Validator::make(Input::all(), $rules);

if($validator->fails()){
    return Redirect::to('contact')->withInput()->withErrors($validator);
}else{

    $data = array('name' => Input::get('name'),
                  'email' => Input::get('email'),
                  'text' => Input::get('message'),
                  'subject' => Input::get('subject'));  

    Queue::push('ContactQueue', $data);

    return Redirect::to('contact')->with('success', 'Message sent successfully');
}

I am trying to write a unit test for the success scenario, I have the following:

public function testSuccess(){
    Validator::shouldReceive('make')->once()->andReturn(Mockery::mock(['fails' => false]));

    Queue::shouldReceive('push')->once();

    $this->call('POST', '/contact');

    $this->assertRedirectedTo('/contact');
}

But I keep receiving the following error when trying to run phpunit:

BadMethodCallException: Method Illuminate\Queue\QueueManager::connected() does not exist on this mock object

Any ideas?


Source: (StackOverflow)

Mockery false positive in Laravel controller test

I'm trying to learn how to use Mockery with Laravel 5. I've based my efforts mostly on Way's book (Laravel Testing Decoded) and other tutorials, which say integration [with PHPUnit] only requires the tearDown() method. So I've included that. The problem is that it doesn't seem to be resetting things between tests. My test class contents look essentially like this:

public function __construct()
{
    $this->mock = Mockery::mock('Class\To\Mock');
}

public function tearDown()
{
    Mockery::close();
}

public function test_RedirectWithoutAuthentication()
{
    // Act
    $this->call('GET', '/path/1');

    // Assert
    $this->assertRedirectedTo('/auth/login');
}

public function test_X()
{
    // Arrange
    $this->mock->shouldReceive('MockedClassMethod')->once();

    // Act
    $this->call('GET', '/path/1');
}

The first test works and the Auth middleware kicks the user to the login page. In the interest of TDD, I've written the second test before the MockedClassMethod is actually written. So to my way of thinking, it should fail spectacularly. But it doesn't. It passes!

If I change the order of the tests, it "works" (unwritten fails, auth passes) which leads me to believe that it's not really an order problem, but something to do with one test not getting cleaned up before the next.

Any insights will save my remaining hair from being pulled out. :-)


Source: (StackOverflow)

Class 'Mockery' not found

I use laravel (4.1) framework and i read "Laravel-testing-decoded", it's a ebook by Jeffrey Wey.

I want to test my modal User and my method setPasswordAttribute($password)

My unit-testing :

<?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);
    }
}

But when i launch CLI : phpunit it return me a error : Fatal error: Class 'Mockery' not found

In complete error :

    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    3946968   7. PHPUnit_Framework_TestSuite->runTest() /Applications/MAMP/htdocs/ptf/vendor/phpunit/phpunit/PHPUnit/Framework/TestSuite.php:745
        0.0742    3947000   8. PHPUnit_Framework_TestCase->run() /Applications/MAMP/htdocs/ptf/vendor/phpunit/phpunit/PHPUnit/Framework/TestSuite.php:775
        0.0743    3948232   9. PHPUnit_Framework_TestResult->run() /Applications/MAMP/htdocs/ptf/vendor/phpunit/phpunit/PHPUnit/Framework/TestCase.php:783
        0.0754    4005504  10. PHPUnit_Framework_TestCase->runBare() /Applications/MAMP/htdocs/ptf/vendor/phpunit/phpunit/PHPUnit/Framework/TestResult.php:648
        0.2926   15417592  11. PHPUnit_Framework_TestCase->runTest() /Applications/MAMP/htdocs/ptf/vendor/phpunit/phpunit/PHPUnit/Framework/TestCase.php:838
        0.2926   15418872  12. ReflectionMethod->invokeArgs() /Applications/MAMP/htdocs/ptf/vendor/phpunit/phpunit/PHPUnit/Framework/TestCase.php:983
        0.2926   15418904  13. UserTest->testHashesPasswordWhenSet() /Applications/MAMP/htdocs/ptf/vendor/phpunit/phpunit/PHPUnit/Framework/TestCase.php:983
        0.2928   15426728  14. Illuminate\Support\Facades\Facade::shouldReceive() /Applications/MAMP/htdocs/ptf/app/tests/models/UserTest.php:7
        0.2928   15426944  15. Illuminate\Support\Facades\Facade::createFreshMockInstance() /Applications/MAMP/htdocs/ptf/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php:50
        0.2928   15427040  16. Illuminate\Support\Facades\Facade::createMockByName() /Applications/MAMP/htdocs/ptf/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php:64

I don't understand, why i have this error.


Source: (StackOverflow)

Class 'Eloquent' not found when mocking in Laravel

I'm following through Jeffrey Way's Laravel Testing Decoded and I've hit an issue I can't seem to fix.

I'm actually work through this tutorial: http://net.tutsplus.com/tutorials/php/testing-laravel-controllers/ Which is an excerpt from his book.

Basically I have a test like so:

class PostsTest extends TestCase {


    public function __construct() 
    {
        $this->mock = Mockery::mock('Eloquent', 'Post');        
    }

And that like for mocking Eloquent and Post returns:

PHP Fatal error:  Class 'Eloquent' not found

When I run phpunit. Incidentally if I use Jeffrey's Laravel Generators and just generate some scaffold e.g.

php artisan generate:scaffold post --fields="title:string, body:string"

And run phpunit I get same error. He's using the same:

$this->mock = Mockery::mock('Eloquent', 'Post');

To mock the classes. Does anyone have any suggestions on what the issue could be?


I've been working through the tutorial again from scratch and am still getting the same error. I've pushed it to a public repo so people can see: https://github.com/RyanHavoc/tdd-laravel

Just pull it down, run composer install/update and phpunit.


Source: (StackOverflow)