Ben Harold
Ben Harold

Reputation: 6432

What is the best practice for substituting config parameters during testing?

I'm testing a method that uses a public key to encrypt a social security number before it is saved to a database. It looks like this:

public function setSsnAttribute($value)
{
    // Load the public key
    $public = file_get_contents(Config::get('certificates.public'));

    // Attempt to encrypt the social security number using the public key
    if (!openssl_public_encrypt($value, $crypted, $public))
    {
        throw new Exception('Could not encrypt data. Nothing was stored.');
    }

    // The value of $crypted returned by openssl_public_encrypt contains
    // binary characters. Rather than storing the data in a BLOB, I'm
    // electing to use base64 encoding to convert it to a string that is
    // suitable for storage in the database.
    $crypted = base64_encode($crypted);

    $this->attributes['ssn'] = $crypted;
}

The issue is with the Config::get('certificates.public') call. I want to make sure that the appropriate exception is thrown if the encryption step fails. The value from Config::get('certificates.public') returns the path to the public certificate that is defined in a config file. My thinking is that the simplest way to test the exception would be to provide a bad path for the public certificate.

I could define an additional parameter in my config file. I'm thinking something along the lines of certificates.test.public.bad would return /dev/null or something like that.

What is the best practice for specifying alternate config parameters during unit testing? Loading the path to the certificate within the setSsnAttribute method seems suspect to me. Is there a more testing-friendly way to load config parameters?

Upvotes: 0

Views: 65

Answers (1)

Ben Harold
Ben Harold

Reputation: 6432

After going back to the Laravel documentation, I realized that I can override any config parameters I need to by simply calling Config::set() on the parameter from within the unit test. For example:

/**
 * @expectedException Exception
 */
public function testSsnDecryptionFailureThrowsException()
{
    // Replace the private certificate with
    Config::set('certificates.private', '/dev/null');

    $application = FactoryMuff::create('Lease317\RentalApplication');

    // I must access the attribute in order to trigger the decryption
    $application->ssn;
}

This works as expected and now I have 100% code coverage on the model.

Upvotes: 1

Related Questions