1

I am in the process of implementing an API for the OPTIONS request for a pre-flight check on CORS calls.

The Allowed-Origins host between local, test and prod will all be different so I moved this to a dotenv file.

Now though when I create my unit test to validate this there is an issue

Lets say that local has a value of localhost:3000 but test has test.site.com and prod is site.com

So now the test that verify headers

assertTrue(response.getHeaders()["Access-Control-Allow-Origin"][0]==="localhost:3000")

Will only pass in local.

A couple ideas I had and reason I think they would not cover the cases:

Hard code like above each env condition would leave failing test in other environment.

Load the env files and validate that but this is useless because I am confirming the file equals the file.

Load the env file for each env and hardcode the expectation in the assert. Could work the plan is not to have local or prod in test.

asked Jan 15, 2020 at 3:53
2
  • 1
    Tests should be written with a given test rig in mind. It is possible to describe a test rig that makes a production deployment and a local test rig look identical, but I would avoid that. It is far too easy for a developer to write a destructive/mutative test expecting it to only be run against a throwaway build. This is why we make the distinction between dev tests, and deployment tests - even if they superficially look identical. Written as a dev test, hard code the url, it simplifies development. Written as a deployment test, use a configuration object obtained somehow. Commented Jan 15, 2020 at 4:34
  • @Kain0_0 never looked into deployment tests. Seems like this may be a path I go down for this goal. Commented Jan 15, 2020 at 13:20

2 Answers 2

1

What do you want to verify in your test?

  • If you want to verify that the Access-Control-Allow-Origin header is correctly filled according to the environment you are running in, then you should exactly read the expected value from the dotenv file, so you can know that its value is filled in correctly in the header.

    You would need a proper review process to ensure that the value stored in the dotenv file is actually correct.

  • If you want to verify that the Access-Control-Allow-Origin header matches one of "localhost:3000","test.site.com" or "site.com", then you should write a test for that, but such a test would not verify that the correct value for the current environment gets used. The test would also need to be updated if the URL of an environment changes or a new URL gets added.

answered Jan 15, 2020 at 11:48
1
  • From my perspective the first case is testing that the file matches the file which seems fruitless in my opinion because of course it will. Also, a review process would include me, myself and I and I trust none of those guys. I want the test to break like the second case states because then I know I changed something and need to go check but then the trap of a set of test per an env or all envs tested in one place? Commented Jan 15, 2020 at 13:18
1

"The environment" usually has the same interface as a Map/Dictionary, or a lookup function -- you pass in a string, you get a string returned.

// getenv: String -> String
String path = System.getenv("PATH")

My first choice is generally to run the tests in the correctly specified environment. After all, that's what the environment is for.

But if I need to test different environments, then what I'll normally do is partition my code into two parts; one part that knows that environment variables are fetched using System.getenv, and a second part that knows which environment variables we get and what we do with them.

doSomethingInteresting(x: X, y: Y, z: Z) {
 // because this method is so simple, the risk of a mistake is low
 // especially in a language where we have strong type checking
 doSomethingInteresting(x, y, z, System::getenv)
}
doSomethingInteresting(x: X, y: Y, z: Z, getenv: String -> String) {
 // This method is potentially very complicated, and cares about
 // which values are returned by getenv, but it doesn' particularly
 // care whether we pass in the real getenv, or a substitute
 // ...
}

My "unit tests" that need to customize the environment invoke the second version of the function, where all of the risk is concentrated.

Passing getenv around is a lot of hammer; if we have a simple nail, then maybe we can do the same thing on a smaller scale. For example

doSomethingInterestingWithThePath(x: X, y: Y, z: Z) {
 // we don't need to test this
 doSomethingInterestingWithThePath(x, y, z, System.getenv("PATH"))
}
doSomethingInterestingWithThePath(x: X, y: Y, z: Z, path: String) {
 // instead we test this
 // ...
}

As an implementor, you are expected to make design choices that ensure that testing your implementation is cost effective....

answered Jan 15, 2020 at 13:56
1
  • Thank you for the answer. It triggered a thought. I have resources for each env now to specify what to expect in those environments. It lets me check per env which is what I wanted. Prod is still tricky. Commented Jan 20, 2020 at 15:14

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.