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
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
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
kpanic
Hi everyone, I am toying with the idea of building a “match maker” for giving personal help to people that wants to start coding. I sta...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
asweet-confluent
I recently noticed that Elixir’s Logger defaults its primary log level to :debug when no :logger, :level application configuration is pre...
New
mnkhod
So i have been using ash framework for a while and i love it. However currently the issue im having with ash framework is the error handl...
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
JesseHerrick
Hey, I’m Jesse and I’m the main contributor behind Dexter, a full-featured, lightning-fast Elixir LSP optimized for large codebases. It s...
New
mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
mhanberg
Hi everyone! The first release candidate for the Expert language server project is now available! We’ve published a press release detai...
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

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews