PHPFixing
  • Privacy Policy
  • TOS
  • Ask Question
  • Contact Us
  • Home
  • PHP
  • Programming
  • SQL Injection
  • Web3.0
Showing posts with label mocking. Show all posts
Showing posts with label mocking. Show all posts

Sunday, September 4, 2022

[FIXED] How to logout user in Laravel functional tests?

 September 04, 2022     authentication, laravel, mocking, testing     No comments   

Issue

In Laravel feature tests,

Given that user has been programmatically logged in using

$this->actingAs(self::$user, 'api');

How would I logout this user?
actingAs does not accept null as first parameter.


Solution

A good way to logout the user is

$guard = Mockery::mock(Guard::class);
$guard->expects('check')
        ->andReturns(false);

Auth::shouldReceive('guard')
       ->andReturns($guard);


Answered By - Florent Brassart
Answer Checked By - Senaida (PHPFixing Volunteer)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

Wednesday, May 18, 2022

[FIXED] How do you not do partial mocking in this scenario?

 May 18, 2022     java, mocking, partial, unit-testing     No comments   

Issue

Let's say I wrote a pretty simple class called ValueFinder that looks like this:

public class ValueFinder {

    public String findValue(Object obj) {
        String value = null;
        value = findValueFirstWay(obj);
        if (value == null) {
            value = findValueSecondWay(obj);
        }
        return value;
    }

    protected String findValueFirstWay(Object obj) {
        ....
    }

    protected String findValueSecondWay(Object obj) {
        ....
    }
}

Now I want to test that findValueFirstWay is really the first method attempted when calling findValue. This is a very simple class, the "algorithms" of the ways are very simple. Without doing a partial mock where findValueFirstWay and findValueSecondWay are mocked and findValue is left alone, how do I test that?

I assume I'm supposed to refactor the class so that findValueFirstWay and findValueSecondWay are in a separate class or classes? It just seems like unnecessary work for something so simple.


Solution

You could avoid mocking entirely and test it by the visible effect with real objects.

Or you could mock the objects being passed in as values, and expect whatever calls that the findValueFirstWay(Object obj) makes to the obj that cause it to return a null, etc.

However, even though it seems simple, my first impulse would still be to extract the problem methods to a separate class or two, so that the interaction can be more naturally tested with mocks.



Answered By - Don Roby
Answer Checked By - Robin (PHPFixing Admin)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

Monday, May 16, 2022

[FIXED] How can I mock outputting messages to the error log with PHPUnit?

 May 16, 2022     automated-tests, error-logging, mocking, php, phpunit     No comments   

Issue

In this answer it mentions using expectOutputString() to, well, expect output strings in PHPUnit.

I also need to do sort of the counterpart of this, which is to tell a mock to output a string.

I was previously using $mock->will($this->throwException(Exception('foo')) to have my mock throw an exception but now instead of throwing an exception I need it to log the error and NOT re-throw the exception, which means I need my mock to output a string just as error_log() does in the method I'm trying to mock, so that my test can expect the string.

Does this make sense? Is it possible to do? Does PHPUnit offer a way to do it?


Solution

From the testability point of view, it's always better to abstract the error logging into a class. If you make direct calls to error_log() you will have difficulties checking the calls made.

If you can't refactor your code and use a class for logging errors, you could try setting a custom error handler that will store the messages in some place, and then check those messages at the test, after the relevant call.

But if you can, it's better to create a class with methods that abstract native php error logging. This class will be a dependency of the class under test. You can either pass it as a constructor mandatory argument, or have the class create it automatically, but allow to set it externally. Obviously, in the test you would inject a mock of that "ErrorLogger" class with expectations



Answered By - gontrollez
Answer Checked By - Terry (PHPFixing Volunteer)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

Thursday, April 28, 2022

[FIXED] How to Fix: deprecation warning of 'any_instance'

 April 28, 2022     mocking, rspec, ruby-on-rails, ruby-on-rails-4, warnings     No comments   

Issue

My question

The scenario it works but in the console when I run the tests (bin/rspec) I get this warning:

Deprecation Warnings:

Using any_instance from rspec-mocks' old :should syntax without explicitly enabling the syntax is deprecated. Use the new :expect syntax or explicitly enable :should instead. Called from /home/wakematta/github/example/spec/features/aspec/features/premium_spec.rb:3:in `block (2 levels) in '.

If you need more of the backtrace for any of these deprecations to identify where to make the necessary changes, you can configure config.raise_errors_for_deprecations!, and it will turn the deprecation warnings into errors, giving you the full backtrace.

1 deprecation warning total

My scenario

app/controllers/application_controller.rb

class ApplicationController < ActionController::Base
  include ExtraContent
end

app/controllers/concerns/extra_content.rb

module ExtraContent
  extend ActiveSupport::Concern

  included do
    helper_method :extra_content?
  end

  def extra_content?
    current_user.premium?
  end
end

app/views/users/show.html.haml

%h1= @user.name
- if extra_content?
  %span.premium PREMIUM

spec/features/premium_spec.rb

feature 'Premium features' do
  scenario 'premium user can view extra content' do
    ApplicationController.any_instance.stub(:extra_content?).and_return(true)

    visit '/users/1'
    expect(page).to have_content 'PREMIUM'
  end
end

Solution

Change this:

spec/features/premium_spec.rb

feature 'Premium features' do
  scenario 'premium user can view extra content' do
    ApplicationController.any_instance.stub(:extra_content?).and_return(true)

    visit '/users/1'
    expect(page).to have_content 'PREMIUM'
  end
end

For this:

spec/features/premium_spec.rb

feature 'Premium features' do
  scenario 'premium user can view extra content' do
    allow_any_instance_of(ApplicationController).to receive(:extra_content?).and_return(true)

    visit '/users/1'
    expect(page).to have_content 'PREMIUM'
  end
end


Answered By - Mohamed Ziata
Answer Checked By - David Marino (PHPFixing Volunteer)
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

Sunday, February 27, 2022

[FIXED] Mock view helper in Yii2 in PHPUnit test

 February 27, 2022     mocking, php, phpunit, yii, yii2     No comments   

Issue

I want to test a specific controller action in Yii2 framework. This action render view file that use helper yii\helpers\Url:

Url::toRoute('page')

When unit test call this view I have error:

yii\base\InvalidArgumentException: Unable to resolve the relative route: vendor/bin/. No active controller is available.

Test:


<?php

use app\modules\user\controllers\UserController;

class UserControllerTest extends \PHPUnit_Framework_TestCase
{
    public function testActionIndex() {

        Yii::configure(Yii::$app, [
            'components' => [
                'user' => [
                    'class' => 'yii\web\User',
                    'identityClass' => 'app\modules\user\models\User',
                ],
                'request' => [
                    'class' => 'yii\web\Request',
                    'cookieValidationKey' => 'abc',
                ],
            ],
        ]);

        $controller = new UserController('user', Yii::$app);
        $result = $controller->run('index', []);
    }
}

How can I mock method Url::toRoute in view to avoid this error?


Solution

Url helper uses Yii::$app->controller for resolving relative routes. You need to set Yii::$app->controller before you call your action:

Yii::$app->controller = new UserController('user', Yii::$app);
$result = Yii::$app->controller->run('index', []);

Alternatively you may avoid this problem using absolute routes:

Url::toRoute('/mymodule/mycontroller/page');

Although it is quite impractical, since you will need to repeat the same route in many places.



Answered By - rob006
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

Monday, February 21, 2022

[FIXED] Laravel Mock Request function only and header

 February 21, 2022     laravel, mocking, php, phpunit, unit-testing     No comments   

Issue

I test code with PHPUnit 9.0. I use Laravel framework 8.* and PHP 7.4

I struggle to test a function that uses request()

Here is a very short version of the code I have to test:

trait SomeTrait
{

  function someFunction()
  {
     //1. retrieve only the documents
     $documents = request()->only('documents');

     ....

     //set an array called $header
     $header = [ 'Accept-Encoding' => 'application/json'];

     //2. add to Array $header if someKey is available in headers
     if (request()->headers->has('someKey'))
     {
       $header = Arr::add($header, 'someKey', request()->header('someKey'));
     }
   }
}

At first (1.) it has to get the documents from a request. I solved this with an mock of the request and it works:


$requestMock = Mockery::mock(Request::class)
            ->makePartial()
            ->shouldReceive('only')
            ->with('documents')
            ->andReturn($document_data);
        app()->instance('request', $requestMock->getMock());

$this->someFunction();

I create a mock of request class, that returns $document_data when request()->only('documents'); is called in someFunction().

But then the code request()->headers->has('someKey') returns the error: Call to a member function has() on null

Can anybody help and explain how I can test the code?


Solution

Thanks for the help! I found a solution without mocking the request - sometimes it's easier than you think :D

//create a request 
$request = new Request();

//replace the empty request with an array
$request->replace(['documents' => $all_documents]);

//replace the empty request header with an array
$request->headers->replace(['someKey' => 'someValue']);

//bind the request
app()->instance('request', $request);


Answered By - Nele
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

Sunday, February 20, 2022

[FIXED] Laravel Mock Request function only and header

 February 20, 2022     laravel, mocking, php, phpunit, unit-testing     No comments   

Issue

I test code with PHPUnit 9.0. I use Laravel framework 8.* and PHP 7.4

I struggle to test a function that uses request()

Here is a very short version of the code I have to test:

trait SomeTrait
{

  function someFunction()
  {
     //1. retrieve only the documents
     $documents = request()->only('documents');

     ....

     //set an array called $header
     $header = [ 'Accept-Encoding' => 'application/json'];

     //2. add to Array $header if someKey is available in headers
     if (request()->headers->has('someKey'))
     {
       $header = Arr::add($header, 'someKey', request()->header('someKey'));
     }
   }
}

At first (1.) it has to get the documents from a request. I solved this with an mock of the request and it works:


$requestMock = Mockery::mock(Request::class)
            ->makePartial()
            ->shouldReceive('only')
            ->with('documents')
            ->andReturn($document_data);
        app()->instance('request', $requestMock->getMock());

$this->someFunction();

I create a mock of request class, that returns $document_data when request()->only('documents'); is called in someFunction().

But then the code request()->headers->has('someKey') returns the error: Call to a member function has() on null

Can anybody help and explain how I can test the code?


Solution

Thanks for the help! I found a solution without mocking the request - sometimes it's easier than you think :D

//create a request 
$request = new Request();

//replace the empty request with an array
$request->replace(['documents' => $all_documents]);

//replace the empty request header with an array
$request->headers->replace(['someKey' => 'someValue']);

//bind the request
app()->instance('request', $request);


Answered By - Nele
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

Monday, January 31, 2022

[FIXED] Undefined method on mock object implementing a given interface in PHPUnit?

 January 31, 2022     mocking, php, phpunit, symfony, unit-testing     No comments   

Issue

I'm new to unit testing and PHPUnit.

I need a mock, on which I have a full control, implementing ConfigurationInterface interface. Test subject is ReportEventParamConverter object and test must check the interaction between my object and the interface.

ReportEventParamConverter object (here simplified):

class ReportEventParamConverter implements ParamConverterInterface
{
    /**
     * @param Request $request
     * @param ConfigurationInterface $configuration
     */
    function apply(Request $request, ConfigurationInterface $configuration)
    {
        $request->attributes->set($configuration->getName(), $reportEvent);
    }

    /**
     * @param ConfigurationInterface $configuration
     * @return bool
     */
    function supports(ConfigurationInterface $configuration)
    {
        return 'My\Namespaced\Class' === $configuration->getClass();
    }
}

And this is the way I'm trying to mock the interface:

$cls = 'Sensio\Bundle\FrameworkExtraBundle\Configuration\ConfigurationInterface';
$mock = $this->getMock($mockCls);

I need to simulate the returned values for two methods: getClass() and getName(). For example:

$mock->expects($this->any())
    ->method('getClass')
    ->will($this->returnValue('Some\Other\Class'))
;

When i create a new ReportEventParamConverter and test supports() method, i get the following PHPUnit error:

Fatal error: Call to undefined method Mock_ConfigurationInterface_21e9dccf::getClass().

$converter = new ReportEventParamConverter();
$this->assertFalse($converter->supports($mock));

Solution

It's because there is no declaration of "getClass" method in ConfigurationInterface. The only declaration in this interface is method "getAliasName".

All you need is to tell the mock what methods you will be stubing:

$cls = 'Sensio\Bundle\FrameworkExtraBundle\Configuration\ConfigurationInterface';
$mock = $this->getMock($cls, array('getClass', 'getAliasName'));

Notice that there is no "getClass" declaration but you can stub/mock non existing method as well. Therefor you can mock it:

$mock->expects($this->any())
    ->method('getClass')
    ->will($this->returnValue('Some\Other\Class'));

But in addtion you need to mock "getAliasName" method as well as long as it's interface's method or abstract one and it has to be "implemented". Eg.:

$mock->expects($this->any())
   ->method('getAliasName')
   ->will($this->returnValue('SomeValue'));


Answered By - Cyprian
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg

Friday, January 28, 2022

[FIXED] Laravel/codeception testing: how to stubbing time()

 January 28, 2022     codeception, laravel, mocking, php, stubbing     No comments   

Issue

Is it possible using Laravel mocking, stubling, (and/or Codeception\Test\Unit and/or Codeception\Stub) to make test for method z (public testZ(){...} ) for following class:

<?php

class X extends Y
{
    public function z(string $c = 'c') : array
    {
        return [$c, time()];
    }
}

So, I need time() to return fake value. Uopz & mimus are excluded options (coz it is possible that sooner or later it can be abandoned).

Is there any Laravel/php trick to make reliable test for codes that returns time() as part of returned value?


Solution

If you convert it to Carbon datetime, there is possibilities.

return [$c, now()->timestamp];

Now you can set your fake date in a test and it will return given date when used in the code

Carbon::setTestNow(Carbon::create(2021, 10, 19, 9, 30);


Answered By - mrhn
Read More
  • Share This:  
  •  Facebook
  •  Twitter
  •  Stumble
  •  Digg
Older Posts Home
View mobile version

Total Pageviews

Featured Post

Why Learn PHP Programming

Why Learn PHP Programming A widely-used open source scripting language PHP is one of the most popular programming languages in the world. It...

Subscribe To

Posts
Atom
Posts
All Comments
Atom
All Comments

Copyright © PHPFixing