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

Blokh
Hey guys, I’ve got a huge CSV ( around 10 GB ) that needs to be processed hourly Do you guys have any suggestions what is the best prac...
New
kszambelanczyk
Hello! Could someone please give me a help/sample code, how to delete a file from s3 using waffle/waffle_ecto from Phoenix app. I creat...
New
Onor.io
I have what I’ve heard referred to as a “lookup table” in my database. This is a way of assigning codes to common values. One common lo...
New
Trolleger
What approach to take when sending live updates to “random” users Hi! I have a question, I have a little chat app, and when I create a DM...
New
matt-savvy
Anyone here using Honeybadger? My Honeybadger account is being overwhelmed with noise from some bots. Seeing a lot of Bandit.HTTPError...
New
RemyXRenard
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
samoloth
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New

Other Trending Topics Top

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
mcass19
ExRatatui lets you cook up rich terminal UIs in Elixir, powered by Rust’s ratatui via Rustler NIFs. Build interactive terminal applicatio...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge & Solve. They are GUI (Emerge) and State management (S...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
wintermeyer
There are three potential reasons for members of this forum to have a look at https://vutuv.de You are tired or annoyed of LinkedIn. Yo...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews