Reputation: 11182
I'm implementing some logic that requires code to behave differently in a production environment.
I want to write a test that asserts this actually happens, but I'm having difficulty mocking the environment.
I've seen it suggested to use putenv('APP_ENV=production');
but it doesn't seem to work.
How can I make the test pass?
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);
}
}
Time: 160 ms, Memory: 18.00MB
There was 1 failure:
1) EnvTest::testEnv
Failed asserting that two strings are equal.
--- Expected
+++ Actual
@@ @@
-'production'
+'testing'
Upvotes: 12
Views: 6746
Reputation: 2261
You can use detectEnviroment
to temporarily change the environment variable:
app()->environment('production') // False
app()->detectEnvironment(fn () => 'production');
app()->environment('production') // True
Upvotes: 1
Reputation: 2648
I adapted the answer of @staskrak so the behaviour of the mock is exactly like calling App::environment()
with or without arguments. It also doesn't throw similar errors like 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();
}
Upvotes: 2
Reputation: 743
I know this question is a year old now, but for those who come looking like I did, this worked for me in 5.8
public function test_config_env()
{
$this->app->detectEnvironment(function() {
return 'production';
});
$this->assertEquals('production', app()->environment()); // pass
}
Upvotes: 14
Reputation: 4074
App::environment()
doesn't seem yo be reading from the config file!
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
}
Tested on Laravel v5.3
Upvotes: 4
Reputation: 863
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
}
Upvotes: 5