Mocks and Application Environment

This post is hopefully for clarification with respect to “mocks” and application configuration.

With respect to mocking as described by José in Mocks and Explicit Contracts we leverage Application.get_env(:my_app, :some_key) to provide the correct resource by adding config information to our config files, e.g. dev.exs, prod.exs, test.exs.

This is great, but when your project (proj_a) is a included as a dependency in another project (proj_b) then by default Application.get_env(:proj_a, :some_key) will return nil and code in proj_a that depends on the resource provided by Application.get_env(:proj_a, :some_key) will error. This forum post expands on access to config keys in a package.

We can fix this by adding the “correct” config information for proj_a in the config files of proj_b.

What I am wondering is if my interpretation is correct or am I missing something?

In particular I ran into this because I was using doing dev on my Macbook for something that is Linux file system specific. As a result I created a mock and a mac_dev.exs file to allow me to do my dev on my Macbook while having a mock to provided the expected behavior of the code running on a Linux file system.

That code is fine and works, but when I include it as a dependency for another application and continue working on it the “proj_a” code will break if I do not define the correct proj_a config settings in “proj_b”.

That is fine, I just want to make sure I am doing things the “right” way and my understanding of how things work are correct.

1 Like

I usually use the application startup phase to read all configs and validate them, and if they are missing and a default value makes sense, I write it back. If it makes no sense, I fail starting up, printing a message to stdout/stderror/log.

1 Like

I like that, provides a visibility for for any consumer.

No. Visibility should be provided by documentation.

The problem you describe in this thread is true for any kind of configuration in any framework and language.

Once you make a “thing” configurable instead of hardcoding it, you need to provide documentation about that setting and you need to decide if you want to fail if the setting is missing or if you want to assume sane defaults.

Either (failing or defaulting) is usually done in an abstracted module/class/object/struct/whatever which reads, verifies and applies default values to configuration once.

Agree, chose my words poorly. I like the approach of making sure to validate during application startup and provide either helpful error messages and/or sane defaults, while also providing documentation.