Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

cheah2go's avatar

phpunit error: Constant already defined

I'm fairly new to Laravel and completely new to TDD. I created my first test and just left the default:

    public function testExample()
    {
        $this->assertTrue(true);
    }

It fails with "ErrorException: Constant AUTHORIZENET_API_LOGIN_ID already defined"

I'm defining that constant in a service provider because the Authorize.net API I'm using expects it. I found this:

http://queirozf.com/entries/error-message-constant-already-defined-when-using-phpunit

which sort of makes sense, since the example test runs and passes (I changed the see() call to make it pass), then the second test fails.

Am I doing something wrong with defining the constants? Or is there some way of configuring phpunit so that this won't be a problem?

0 likes
5 replies
ifpingram's avatar
Level 4

Looks like you need to re-architect your code a bit. As a rule you should try to avoid constants in your code wherever possible; I have never had a need to use them in any code I have written. There is usually little need for them and they are sign of badly designed code IMO. This said, it seems that you have followed the instructions in the Authorize.net PHP SDK?

https://github.com/AuthorizeNet/sdk-php

In which case, it is understandable that you are hitting this problem, and it is annoying that their PHP library has been written to use constants. Unfortunately you will need to continue to use the constants, unless you wish to fork and change their library (which you really don't!).

To fix this issue, and follow good Laravel design practice, resolve the data you need from config files: Make a file in ./config directory, named something like authorize-net.php, then include the following:

<?php
return [
    'authorizenet_api_login_id' => env('AUTHORIZENET_API_LOGIN_ID'),
    'authorizenet_transaction_key' => env('AUTHORIZENET_TRANSACTION_KEY'),
    'authorizenet_sandbox' => env('AUTHORIZENET_SANDBOX')
];

Then you can add the 3 environment variables in you .env file like:

AUTHORIZENET_API_LOGIN_ID=your-login-id
AUTHORIZENET_TRANSACTION_KEY=your-transaction-key
AUTHORIZENET_SANDBOX=true

Obviously true for the sandbox in your dev / testing / staging environments, and false for production.

Thereafter, in you code where you set the constants, use the following:

if(!defined('AUTHORIZENET_API_LOGIN_ID')){
    define('AUTHORIZENET_API_LOGIN_ID', config('authorize-net')['authorizenet_api_login_id']);
} 
if(!defined('AUTHORIZENET_TRANSACTION_KEY')){
    define('AUTHORIZENET_TRANSACTION_KEY', config('authorize-net')['authorizenet_transaction_key']);
} 
if(!defined('AUTHORIZENET_SANDBOX')){
    define('AUTHORIZENET_SANDBOX', config('authorize-net')['authorizenet_sandbox']);
} 

This then ensures that you separate your environment configuration nicely from the code (i.e. you don't hard code it and couple your code to your config).

I have not tested the above, as I do not use Authorize.net, but it should work, or put you on the right path; hopefully there are no syntax errors!

Good luck!

2 likes
cheah2go's avatar

Thanks! Yes I'm storing my keys in my .env file, but referencing them directly like this:

    public function register()
    {
        define('AUTHORIZENET_API_LOGIN_ID', env('AUTHNET_API_LOGIN_ID'));
        define('AUTHORIZENET_TRANSACTION_KEY', env('AUTHNET_TRANSACTION_KEY'));
        define('AUTHORIZENET_SANDBOX', env('AUTHNET_SANDBOX'));
        
        $this->app->singleton(Authnet::class, function () {

            return new Authnet(new AuthorizeNetARB);
        });
    }

I didn't think to do a check to see if they were already defined, makes perfect sense. Thank you!

Do you think it is bad to reference the .env values directly, instead of doing it in a config file like you suggested?

ifpingram's avatar

It will of course work to reference them directly in the code, but IMO it is not a good practice to follow, as you will litter your system with .env calls and make it harder to work out how everything is configured and from where.

To ensure good separation of concerns, it is much better to instead litter your system with config() calls and then propagate the config values with the environment variables. Amongst other benefits, this gives you:

  • A well organised layer in between the environment variables and the code;

  • which in turn allows you to add logic to the config system if necessary at a later date*.

  • An easy reference to all the config in the system (as it is in one directory).

:* Apart from supplying a default value, there is no further logic that can be applied to a .env call. As config is loaded from a array returned from a PHP file, you can write as much code as you like to configure it. Granted, 99% of the time it will just be an array that proxy's the values from the .env file, but should the day arise where you need to add some sort of logic to your configuration, you will not be able to without moving everything into a config file; so why not just do it from the beginning in order to plan ahead?

1 like
HectorOrdonez's avatar

I notice this is a 8 years old thread, but I got redirected here while looking for some other problem, and I have to say that using constants is not a bad practice, at least not anymore. For those who end up here and are less experienced, that might be misleading.

Please or to participate in this conversation.