【问题标题】:Mocking laravel environment in test在测试中模拟 laravel 环境
【发布时间】:2018-11-23 10:00:42
【问题描述】:

我正在实现一些要求代码在生产环境中表现不同的逻辑。

我想编写一个测试来断言这确实发生了,但我在模拟环境时遇到了困难。

我已经 seen it suggested 使用 putenv('APP_ENV=production'); 但它似乎不起作用。

我怎样才能使测试通过?

use Illuminate\Support\Facades\App;
use Tests\TestCase;

class EnvTest extends TestCase
{
    public function testEnv()
    {
        // This assertion is fine
        $env = App::environment();
        $this->assertEquals('testing', $env);

        putenv('APP_ENV=production');

        // This assertion fails
        $env = App::environment();
        $this->assertEquals('production', $env);
    }
}

结果

时间:160 毫秒,内存:18.00MB

有 1 次失败:

1) EnvTest::testEnv

断言两个字符串相等失败。

--- 预期

+++实际

@@@@

-'生产'

+'测试'

【问题讨论】:

    标签: php laravel mocking phpunit environment-variables


    【解决方案1】:
    use App;
    
    //...
    
    public function my_awesome_test() 
    {
        // Number of times method environment() have to be invoked
        $number_of_calls_to_method = 2
    
        // Fake, that we have production environment
        App::shouldReceive('environment')
            ->times($number_of_calls_to_method)
            ->andReturn('production');
    
        // Make here whatever you want in Production environment
    }
    

    【讨论】:

    • 很好的答案,但这实际上不起作用。 App::environment() 仍然返回不同的东西。
    • 在 Laravel 7.x 中,我收到了 Mockery_0_Illuminate_Foundation_Application::offsetGet(),但没有指定期望
    【解决方案2】:

    App::environment() 似乎没有从配置文件中读取!

    public function test_config_env()
    {
        $this->app['config']->set(['app.env' => 'production']);
    
        $this->assertEquals('production', $this->app['config']->get('app.env')); // pass
        $this->assertEquals('production', $this->app->environment()); // fail
    }
    
    public function test_env()
    {
        $this->app['env'] = 'production';
    
        $this->assertEquals('production', config('app.env')); // fail
        $this->assertEquals('production', $this->app['config']->get('app.env')); // fail
    
        $this->assertEquals('production', $this->app['env']); // pass
        $this->assertEquals('production', $this->app->environment()); // pass
    }
    

    在 Laravel v5.3 上测试

    【讨论】:

      【解决方案3】:

      我知道这个问题现在已经有一年了,但对于那些看起来像我的人来说,这在 5.8 中对我有用

        public function test_config_env()
        {
          $this->app->detectEnvironment(function() {
            return 'production';
          });
          $this->assertEquals('production', app()->environment()); // pass
        }
      

      【讨论】:

      • 请注意,如果需要 CSRF 令牌,此方法将导致 POST 方法失败并出现 419 错误。我想这是因为在运行单个测试之前应用程序在“测试”环境中启动,并且在测试中禁用了 CSRF 验证。
      • @CorieSlate 我想如果应用程序正在生产中,正在修补的那种低级别的东西会抛出异常。至少这是我使用它的目的。
      【解决方案4】:

      我调整了@staskrak 的答案,因此模拟的行为与调用App::environment() 完全一样,带或不带参数。它还不会抛出类似的错误,例如 Received Mockery_0_Illuminate_Foundation_Application::offsetGet(), but no expectations were specified

      use Illuminate\Support\Arr;
      use Illuminate\Support\Facades\App;
      
      protected function mockEnvironment(string $environment)
      {
          App::shouldReceive('environment')
              ->withAnyArgs()
              ->zeroOrMoreTimes()
              ->andReturnUsing(function ($args) use ($environment) {
                  // Return the current environment if no args are passed
                  if (!$args) {
                      return $environment;
                  }
      
                  // Wrap the args in an array if it's not in array yet
                  if (!is_array($args)) {
                      $args = Arr::wrap($args);
                  }
      
                  // Check if the current environment is in the given args
                  return in_array($environment, $args);
              });
          App::partialMock();
      }
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2022-08-11
        • 2011-01-09
        • 1970-01-01
        • 2015-10-11
        • 2021-04-09
        • 2019-08-02
        • 2018-08-11
        相关资源
        最近更新 更多