What does it mean for a test to be independent? It means that a test should not depend upon the presence or absence of other tests, the order of the tests, or whether or not previous tests failed or not. It also means that the tests should not be dependent upon external things such environment variables, an internet connection, or the local time. Why is it important that tests be independent? If tests are not independent it will lead to a lot of lost time when a test fails when there is nothing wrong with the code and a developer spends a lot of time trying to debug working code. For example if a test uses an environment variable and then a developer runs the test in another system with a different or no value for the environment variable the test might fail due to the environment variable being different, not because there is a bug in the code. The developer might spend a lot of time discovering this. Alternatively a test dependent upon other tests might pass when it should fail causing a bug to go undetected, causing problems in production. For example, one test might set a cell in a table to a certain value. Another test might be supposed to set the same cell to the same value, among other things. If the database is not reset between tests, there would be no way of determining if the second test functioned as it was supposed to. I have seen both of these scenarios recently. Another problem that I have seen recently is tests that depend on an internet connection. Here, if the test fails, we might not know if it was due to momentarily being disconnect from the internet, or something else. The test might pass sometimes and fail some other times, creating confusion and frustration. Other problems can be caused by tests that modify files, call the current time, or share mutables (Of course we need to avoid mutables). I have written a blog post earlier on how to test databases and how to make the tests independent of each other here. Let’s look at how we can test code that uses environment variables.
Environment Variables
A lot of code uses environment variables, and we shouldn’t stop using environment variables just to make testing easier. So how can we test code that uses environment variables? One way could be to create a class with a method to get environment variables and then mock that method to return values that we want. Another way of testing code that uses environment variables is to use a config file. For example in src/main/resources you can put a file called application.conf with the following contents
conn = { url = ${?JDBC_URL} }
Then to get the value of the environment variable JDBC_URL in the local variable url use the following code
import com.typesafe.config._ val conf = ConfigFactory.load() val url = conf.getString("conn.url")
Then for testing purposes you can put another file called application.conf in src/test/resources with the following contents
conn = { url = "jdbc:h2:mem:test" }
Now for your tests the variable url will have the value “jdbc:h2:mem:test” instead of the value of the environment variable JDBC_URL.
Internet Connection
One example of a test which is dependent upon an internet connection is a test of code that tries to create a connection to a database. Such code could be tested using an in-memory database such as H2.
Conclusion
I hope that you have learned something useful. Feel free to leave a comment with feedback or your own experiences with testing.