Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to set environment variables for exactly one test?

Given something like this:

it('uses env variables correctly', function(done) {
    assert.equal(process.env.x * process.env.y, 10);
});

I would like to set the x and y environment variable for this one test only. Is that possible?

like image 999
neverendingqs Avatar asked Nov 13 '16 21:11

neverendingqs


People also ask

When should we set environment variables?

If you're running your application from a shell and don't want the environment variables to stick around, set the environment variables for the current process. If you do want the environment variables to stick around, store them in the user registry.

Are environment variables per process?

Environment variables are set on a per-process basis, but they are inherited by child processes. This means that if you set environment variables in process A, another already running process B will not see these new environment variables.

How do I set environment variables permanently?

You can set an environment variable permanently by placing an export command in your Bash shell's startup script " ~/.bashrc " (or "~/.bash_profile ", or " ~/.profile ") of your home directory; or " /etc/profile " for system-wide operations. Take note that files beginning with dot ( . ) is hidden by default.


1 Answers

Here is a very common pattern (as answered by Leonid Beschastny).

describe('env', function () {
  let envCache

  // mocking an environment
  before(() => {
    envCache = process.env;
  })

  // running tests
  it('reads env variables correctly', () => {
    process.env.x = 2
    process.env.y = 5

    assert.equal(process.env.x * process.env.y, 10)
  })

  // process.env is not just a plain object
  it('should convert undefined to a string', () => {
    process.env.UNDEF = undefined

    assert.equal(process.env.UNDEF, 'undefined')
  })

  // Trying to restore everything back
  after(() => {
    process.env = env
  })
})

There is a problem here, however. process.env is not a normal object. If the second test is run in isolation, it will pass, as that is how process.env is supposed to work. If instead we run the whole test suite, the second test will fail!

Setting up your tests like that will cause different behaviors based on how you run the test. This is a very bad thing.

Instead you should use delete to clear the values, and then reassign them like so:

describe('env', function () {
  let envCache

  // mocking an environment
  before(() => {
    envCache = process.env;
  })

  // running tests
  it('reads env variables correctly', () => {
    process.env.x = 2
    process.env.y = 5

    assert.equal(process.env.x * process.env.y, 10)
  })

  // process.env is not just a plain object
  it('should convert undefined to a string', () => {
    process.env.UNDEF = undefined

    assert.equal(process.env.UNDEF, 'undefined')
  })

  // Trying to restore everything back
  after(() => {
    Object.keys(process.env).forEach((key) => { delete process.env[key] })
    Object.entries(envCache).forEach(([ key, value ]) => {
      if (key !== undefined) {
        process.env[key] = value
      }
    })
  })
})

This will keep the behavior more consistent, in case someone forgets that you shouldn't assign a key of process.env to be undefined instead of deleting them.

like image 63
Ustice Avatar answered Sep 27 '22 20:09

Ustice