bkuhl's avatar

How do I mock app() in a framework unit test

I'm working on a pull request for attribute casting in eloquent and am running into a scenario where a unit test can't resolve a class out of app() and I'm unsure how to mock it. How can I mock app()?

Fatal error: Call to a member function getBindings() on null in /Users/bkuhl/Personal/framework/src/Illuminate/Database/Eloquent/Model.php on line 2825


    protected function castAttribute($key, $value)
    {
        $castType = $this->getCastType($key);

        // Some objects aren't stored as json so we'll skip those
        // here so they'll get handled accordingly later
        if (!in_array($castType, ['date', 'datetime'])) {
            if (class_exists($this->casts[$key])) {
                return $this->resolveCastedAttribute($this->casts[$key], $value);
            }

            if (in_array($key, app()->getBindings())) {
                return $this->resolveCastedAttribute($key, $value);
            }
        }

        if (is_null($value)) {
            return $value;
        }

        switch ($castType) {
            case 'int':
            case 'integer':
                return (int) $value;
            case 'real':
            case 'float':
            case 'double':
                return (float) $value;
            case 'string':
                return (string) $value;
            case 'bool':
            case 'boolean':
                return (bool) $value;
            case 'object':
                return $this->fromJson($value, true);
            case 'array':
            case 'json':
                return $this->fromJson($value);
            case 'collection':
                return new BaseCollection($this->fromJson($value));
            case 'date':
            case 'datetime':
                return $this->asDateTime($value);
            case 'timestamp':
                return $this->asTimeStamp($value);
        }
    }

The source is here: https://github.com/bkuhl/framework/commit/b57d8ebbe3da80e49be6d310b08cc09c565b7ecc

0 likes
3 replies
bkuhl's avatar

Thanks for taking the time to follow up.

I submitted a pull request for this to get more insight as taylor instructed me to on Twitter. It helped me realize that the reason this functionality isn't offered is because there's intentional decoupling of the IOC container and eloquent. See https://github.com/laravel/framework/pull/11225

wired00's avatar

very old question i know, but incase someone else stumbles on this and needs a solution... i suggest using App facade instead of app()->make() or resolve().

you can then mock the facade in tests, something like:

        App::shouldReceive('make')
            ->andReturn($something);

maybe I'm missing something but i'm not sure why App facade isn't promoted more in laravel documentation

Please or to participate in this conversation.