Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mockery\Exception\BadMethodCallException: Method Mockery_0__does not exist on this mock object #1203

Open
drewg2009 opened this issue Jan 6, 2023 · 0 comments

Comments

@drewg2009
Copy link

When running phpunit I get the following error:

Mockery\Exception\BadMethodCallException: Method Mockery_0__Tests_Unit_App_Utils_Blueprints_BlueprintRuleUtil::executeActiveBlueprintRules() does not exist on this mock object
The test method that is failing is:

public function testExecuteActiveBlueprintRulesShouldExecuteDefaultOutsourceCostRule()
 {

     Strategy::fake();

     Strategy::create(['id' => 1]);
     $createdStrategy = Strategy::getCreatedModel();

     /**
      * We can use a partial mock for BlueprintRuleUtil so we can mock specific methods
      * later on using shouldReceive while still being able to call regular methods on the class
      * including the one we are testing in this test case.
      */
     $blueprint_rule_util_partial_mock = \Mockery::mock(App\Utils\Blueprints\BlueprintRuleUtil::class)->makePartial();

     /**
      * For method chaining with the DB facade
      * we want to use mockery to mock each chained method
      * and use andReturnSelf() to return an instance of the
      * returned value until we reach the last method call in the chain.
      *
      * Then we can return the final result that we should be expecting
      * which is likely a stdClass object as a query result.
      */
     $active_blueprint_rule = new stdClass();
     $active_blueprint_rule->id = 1001;

     DB::shouldReceive("table")
         ->with('blueprint_rules')
         ->once()->andReturnSelf();

     DB::shouldReceive("where")
         ->with('is_active', true)
         ->andReturnSelf();

     DB::shouldReceive("get")
         ->andReturn([$active_blueprint_rule]);

     $blueprint_rule_util_partial_mock->shouldReceive('addDefaultOutsourceCostToStrategy')
         ->withAnyArgs();
     $blueprint_rule_util_partial_mock->shouldReceive('shouldAddDefaultOutsourceCost')->withAnyArgs()->andReturn(true);

     $blueprint_rule_util_partial_mock->executeActiveBlueprintRules($createdStrategy);

     Strategy::stopFaking();
 }

Here is the full test class I am using:

<?php

namespace Tests\Unit;

/*
 *  need to use built in laravel testcase instead of PHPUnit testcase to have access to instance variables like app for mocking
 */

use Tests\TestCase;
use App\Strategy;
use App\Pillar;
use App\Utils\Blueprints\BlueprintRuleUtil;
use DB;
use stdClass;

class BlueprintRuleUtilTest extends TestCase
{

    /**
     * Test to make sure outsource cost will not be added
     * with a certain blueprint type and pillars.
     */
    public function testShouldAddDefaultSnowflakeOutsourceCostWillReturnFalse()
    {
        Strategy::fake();
        Pillar::fake();

        Strategy::create(['id' => 1]);

        // test core business first
        Pillar::create(['id' => 1, 'slug' => 'core-new-business']);

        $createdStrategy = Strategy::getCreatedModel();
        // set the pillar to be the created model so it can grab it's pillar property later on using a relation
        $createdStrategy->pillar = Pillar::getCreatedModel();

        $blueprint_rule_util = new BlueprintRuleUtil();

        $this->assertFalse($blueprint_rule_util->shouldAddDefaultOutsourceCost($createdStrategy));

        // test service expansion by updating the pillar
        $createdStrategy->pillar->slug = 'service-expansion';
        $this->assertFalse($blueprint_rule_util->shouldAddDefaultOutsourceCost($createdStrategy));

        // test with blueprint type set to project and valid pillar slug
        $createdStrategy->pillar->slug = 'resign';
        $createdStrategy->type = 'project';
        $this->assertFalse($blueprint_rule_util->shouldAddDefaultOutsourceCost($createdStrategy));

        Strategy::stopFaking();
        Pillar::stopFaking();
    }

    /**
     * Test given a valid slug and project type that the
     * Snowflake default outsource cost is added
     */
    public function testShouldAddDefaultSnowflakeOutsourceCostWillReturnTrue()
    {
        Strategy::fake();
        Pillar::fake();

        Strategy::create(['id' => 1]);

        $blueprint_rule_util = new BlueprintRuleUtil();

        // test resign which is a valid pillar
        Pillar::create(['id' => 1, 'slug' => 'resign']);

        $createdStrategy = Strategy::getCreatedModel();
        // test with valid type retainer
        $createdStrategy->type = 'retainer';
        // set the pillar to be the created model so it can grab it's pillar property later on using a relation
        $createdStrategy->pillar = Pillar::getCreatedModel();
        $this->assertTrue($blueprint_rule_util->shouldAddDefaultOutsourceCost($createdStrategy));

        Strategy::stopFaking();
        Pillar::stopFaking();
    }


    public function testExecuteActiveBlueprintRulesShouldExecuteDefaultOutsourceCostRule()
    {

        Strategy::fake();

        Strategy::create(['id' => 1]);
        $createdStrategy = Strategy::getCreatedModel();

        /**
         * We can use a partial mock for BlueprintRuleUtil so we can mock specific methods
         * later on using shouldReceive while still being able to call regular methods on the class
         * including the one we are testing in this test case.
         */
        $blueprint_rule_util_partial_mock = \Mockery::mock(App\Utils\Blueprints\BlueprintRuleUtil::class)->makePartial();

        /**
         * For method chaining with the DB facade
         * we want to use mockery to mock each chained method
         * and use andReturnSelf() to return an instance of the
         * returned value until we reach the last method call in the chain.
         *
         * Then we can return the final result that we should be expecting
         * which is likely a stdClass object as a query result.
         */
        $active_blueprint_rule = new stdClass();
        $active_blueprint_rule->id = 1001;

        DB::shouldReceive("table")
            ->with('blueprint_rules')
            ->once()->andReturnSelf();

        DB::shouldReceive("where")
            ->with('is_active', true)
            ->andReturnSelf();

        DB::shouldReceive("get")
            ->andReturn([$active_blueprint_rule]);

        $blueprint_rule_util_partial_mock->shouldReceive('addDefaultOutsourceCostToStrategy')
            ->withAnyArgs();
        $blueprint_rule_util_partial_mock->shouldReceive('shouldAddDefaultOutsourceCost')->withAnyArgs()->andReturn(true);

        $blueprint_rule_util_partial_mock->executeActiveBlueprintRules($createdStrategy);

        Strategy::stopFaking();
    }
}
Here is the class I am testing against:

<?php

namespace App\Utils\Blueprints;

use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use App\Strategy;
use App\StrategyCost;

class BlueprintRuleUtil
{

    const DEFAULT_OUTSOURCE_COST_RULE_ID = 1001;

    /**
     * Iterate through the active blueprint rules and execute them based on their name
     *
     * @param Strategy $strategy
     *
     */
    public function executeActiveBlueprintRules(Strategy $strategy)
    {
        if (!is_null($strategy)) {
            $active_blueprint_rules = DB::table('blueprint_rules')
                ->where('is_active', true)
                ->get();

            foreach ($active_blueprint_rules as $active_blueprint_rule) {
                if (!is_null($active_blueprint_rule) && $active_blueprint_rule->id === self::DEFAULT_OUTSOURCE_COST_RULE_ID) {
                    BlueprintRuleUtil::addDefaultOutsourceCostToStrategy($strategy, $active_blueprint_rule);
                }
            }
        }
    }


    /**
     * Given a strategy (blueprint)
     *
     * Return true if we should add the default outsource cost to it
     * false if not based on the blueprint type and pillar
     *
     * @param Strategy $strategy
     *
     * @return bool
     */
    public function shouldAddDefaultOutsourceCost(Strategy $strategy)
    {
        $pillar_slugs_to_exclude_for_outsource_costs = [
            'core-new-business',
            'service-expansion'
        ];
        if (
            in_array($strategy->pillar->slug, $pillar_slugs_to_exclude_for_outsource_costs)
            || $strategy->type === 'project'
        ) {
            return false;
        }
        return true;
    }


    /**
     * Create a StrategyCost entry in the db for the provided strategy
     * using the amount from the active blueprint rule to add the default outsource cost.
     *
     * @param Strategy $strategy
     * @param object $active_blueprint_rule
     */
    public function addDefaultOutsourceCostToStrategy(Strategy $strategy, object $active_blueprint_rule)
    {

        if (self::shouldAddDefaultOutsourceCost($strategy)) {
            $department_slug = 'data-intelligence';
            $department = DB::table('departments')
                ->where('slug', $department_slug)
                ->first();

            if (!is_null($department)) {
                $strategy_cost = new StrategyCost;
                $strategy_cost->name = 'Snowflake';
                $strategy_cost->department_id = $department->id;
                $strategy_cost->strategy_id = $strategy->id;
                // set first month to outsource cost
                $strategy_cost->month_1 = $active_blueprint_rule->amount;
                $strategy_cost->save();
                $strategy_cost->strategy->recalculate();
            } else {
                Log::debug("BlueprintRuleUtil: department $department_slug not found, did not add default outsource cost");
            }
        }
    }
}

I have tried using the full class name path with the namespace as the argument when creating the partial mock. I thought that might fix it because it may not be loading the right object. However that didn't work.

The method name is in the class that I am mocking. I'm not sure why I continue to get this error.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant