itsok

itsok

I working on a custom mix task (let’s call it mix update_stuff) that assumes the presence of an environment variable (let’s call it FILE_PATH) that holds a path to a file.

When I test the task, I wish to set the path to a temporary value that is specific to a test. I use ExUnit TmpDir for that, more specifically, I create a temporary file inside tmp_dir and then I wish to set the environment variable only for the context of the test to that file.

I’m not sure how to go about this with ExUnit. I come from Ruby world, where it’s possible to simply stub the value on a test level.

The problem I have seems like a generic problem that most probably many engineers have experienced before, but I can’t find a forum post or a blog post with a solution.

Showing Posts 1 to 10

sodapopcan

sodapopcan

You can use Application.put_env/4. Where you put this depends on the test. If it’s ok to exist for the entirety of your test runs you can throw it in test_helper.ex. Otherwise you can put it in a setup with an on_exit callback calling Application.delete_env/3 to clean it up.

katafrakt

katafrakt

Yes, in Ruby it’s super easy to stub stuff, but it’s not necessarily good. In this case a suggestion to use Application.put_env/4 is of course good, but you are losing the ability to run tests async. Also, I would argue this is not very Elixir-ish way to do things.

I know it’s slightly off-topic, but perhaps you don’t need to keep the file name in an env variable? Environmental variables are to keep things about the environment. I know they are widely used in Ruby as a hack to pass data to commands, but copying tricks from other languages is rarely the best way to do things. You could, for example, just pass the file name as an argument to a mix tasks and the testing this would be trivial.

sodapopcan

sodapopcan

@katafrakt is right. I was way too hasty and not very thorough in my response.

Since it is a mix task, you should be ok using Application.put_env assuming you only have one test file and that this is the only task that cares about that ENV var. I would never suggest doing this for application code. Otherwise, I agree with @katafrakt and think it’s better to pass it as an arg if you’re example is not contrived and you’re really talking about a filename. Passing args to Mix is much nicer than it is in Rake. They just work like normal command line args since Mix doesn’t do that weirdness Rake does where each argument is a different task (running multiple tasks in one go is available in Mix via mix do).

Nicd

Nicd

Just a note, Application.put_env/4 deals with application environment (i.e. what you have configured), System.put_env/2 deals with OS environment variables.

sodapopcan

sodapopcan

lol, yes, right. I’m still taking a lot of assumed knowledge for granted here. I’m gonna take a rest :upside_down_face:

itsok

itsok OP

Thanks everyone for thoughtful responses.

As some of you suggested the solution I’m using at the moment involves System.put_env and on_exit. As you’ve pointed out it doesnt’s seem right to go that route, especially because the value is global.

I have three tests that are run async for testing the task, so there is a risk of running into a race condition after repeated runs, it hasnt happened so far during development though.

To give you a bit more context, on my first attempt I implemented a solution where I passed the value directly into the mix task ‘mix update_stuff file/path.txt’, however, I wished for a bit more ergonomic task API, where I store a path into .envrc and load it with dotenv. That way I only need to remember to set the path once and then use the the task simply as ‘mix update_stuff’.

It’s a personal preference, not a hard requirement. It lead me down the path of exploring how would elixir way of achieving such mix task API look like. Perhaps you’ll tell me that putting such arguments into env variables isnt the elixir way indeed. It would be a bit of shame though! :slight_smile:

tfwright

tfwright

If the path to the file is truly different in different deployment environments, then I think storing it in a env var is fine. Your actual code should reference the app config, rather than the system var. Your config can then read that var from system in prod, but hard code it in test.

# prod

config :your_app, mix_file_path: System.get_env("FILE_PATH")

# test

config :your_app, mix_file_path: "/path/to/dummy/file"

That’s all you need if the code doesn’t modify the file. If it does, then you just need to create it fresh in the setup for your test.

al2o3cr

al2o3cr

The simplest way I can think of to accommodate that is to make the path in ENV the default while the task still accepts an argument.

This can solve the testing problem: the tests can pass an explicit argument and not share state, but the everyday user doesn’t have to repeat themselves.

sodapopcan

sodapopcan

I personally don’t think it’s bad. I was picturing you piping it in like this:

$ FILE_PATH=some/path mix task

…which is something I used to do in Rake because rake "task[some/path]" is pretty gnarly.

But if it’s a local task you run a bunch then I would want it in an ENV var as well.

christhekeele

christhekeele

^ This pattern should be avoided, as the FILE_PATH env var will be read when the code is compiled for production, not in the running production environment itself—for example, using releases, or docker to build your app. runtime.exs should be preferred.

Where Next? Top

Trending in Questions Top

katta
I having some trouble figuring out if I have set myself too strict of standards for my production server. Currently I can handle 75% of r...
New
achenet
Hello, I’m trying to build a basic Phoenix web-app, and I’d like to use Tailwind. However, when I launch mix phx.server, I get an error...
New
peck
Hi everyone. My team and I have been working on a fairly modest app based around video streaming and chat, but we’ve landed a customer t...
New
bradley
I really like the adapter patterns that ecto, nebulex, waffle, etc. use and would love find something similar for a key management servic...
New
unaware8150
Hello folks! So at work, we are seeing some situations where we have to define some “fixed” strings that are used across the codebase in...
New
Cxx-mlr
I’m working on a small exercise involving update_in/3, and I came up with this solution: data = %{ name: "Periodic Table", category:...
New
Alvinkariuki
How Can I Optimise Compile Time Dependencies I have been building an elixir application for about 2 years now. Many modules and files ha...
New

Other Trending Topics Top

GenericJam
Edit: 2026 May 15 - This post is archived. Mob is alive!! Main docs: mob v0.7.11 — Documentation A bit of explanation for the slightly c...
New
budgie
A little off-topic, but I feel like people here have a good head on their shoulders. I used to be quite good at making software. Was luc...
New
KristerV
Hey. Is there anyone here who creates agents in their apps? Not talking about using agents, but creating them. I’m finding it pretty diff...
New
mudasobwa
I fully migrated to my own harness from Anthropic/Gemini and I think it’s time to share it. Welcome DSH, the DeepSeek Harness, fully writ...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
juhalehtonen
There has been a thread to discuss the Stack Overflow Developer Survey on this forum every year since 2018, so here’s yet another one for...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews