zekus

zekus

Testing escripts with Sytem.exit()

Hello all.

When writing an Escript that uses System.exit/1 Is there a way to test it?
Or is there a better way to make an Escript return the proper exit code which is testable with ExUnit?

Thanks

Marked As Solved

mbklein

mbklein

Assuming you’re writing this script in a full mix-based environment, I’d probably test this one (or both!) of two ways:

The first would be to make the escript itself a very thin wrapper around the actual functionality it invokes, so that functionality can be tested with more conventional unit tests. You can use Code.compile_file/2 to load and compile your .exs in the test setup, call its main function yourself from inside the test, and unload it after:

defmodule MyScriptTest do
  use ExUnit.Case

  setup do
    Code.compile_file("path/to/escript.exs")
    on_exit(fn ->
      :code.delete(MyEscriptModule)
      :code.purge(MyEscriptModule)
    end)
  end

  test "test the thing" do
    with result <- MyEscriptModule.CLI.main(args) do
      assert something_about(result)
    end
  end
end

The second would be to wrap the System.exit/1 call in its own tiny module:

defmodule MyEscriptModule do
  defmodule Terminator do
    def terminate(status), do: System.exit(status)
  end

  defmodule CLI do
    def main(args) do
      # ... do whatever your script does
      terminate(some_status)
    do

    defp terminate(status) do
      Application.get_env(:my_app, :terminator, Terminator)
      |> Kernel.apply(:terminate, [status])
    end
  end
end

Then in your test, create a mock terminator module you can spy on:

defmodule MyScriptTest do
  use ExUnit.Case

  setup do
    code =
      quote do
        def terminate(status), do: unquote(self()) |> send({:exit_code, status})
      end

    Module.create(TestTerminator, code, file: __ENV__.file)
    Application.put_env(:my_app, :terminator, TestTerminator)

    on_exit(fn ->
      Application.delete_env(:my_app, :terminator)
      :code.delete(TestTerminator)
      :code.purge(TestTerminator)
    end)
  end

  test "test the thing" do
    with result <- MyEscriptModule.CLI.main(args) do
      assert_received({:exit_code, expected_exit_status})
    end
  end
end

There’s probably a much simpler way to structure this, especially the TestTerminator, but I don’t know how you’d get the test process’ PID into the mock without constructing it that way. Someone else might have a tighter example.

Where Next?

Popular in Questions Top

vertexbuffer
Hello, can anybody help here..? I have a list of players and I what to delete an element, but every for loop the list is reverting to ori...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
siddhant3030
Hi, I have to write a raw query for one of my project. But till now I have used ecto queries and don’t have much experience writing raw ...
New
vac
Hi, I’m quite new in Elixir and I’m trying to format a string to a PEM format. I have the certificate value like MIIDBTCCAe2...... and I...
New
ycv005
I have followed this StackOverflow post to install the specific version of Erlang. And When I am running mix ecto.setup then getting fol...
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
Emily
I have VueJS GUIs with the project generated using Webpack. I have Elixir modules that will need to be used by the VueJS GUIs. I forese...
New
aalberti333
As the title describes, I’m trying to run Enum.map() over a list of key/value pairs, where the value is a map. My data looks like this: ...
New
shijith.k
I am trying to start a new phoenix project with elixir 1.9, but mix phx.new does not work. It says that ** (Mix) The task "phx.new" could...
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New

Other popular topics Top

chrismccord
This release brings a number of exciting features, including integration with the new Phoenix LiveDashboard and Phoenix LiveView. There h...
New
vonH
When I run the Plug and I recompile I wind up having to use Ctrl C to quit iex and start again. Witht the help of rlwrap I can use the cu...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
Brian
What is the proper way to load a module from a file in to IEX? In the python world, doing something like this pretty standard: from ....
New
AstonJ
We’ve put together this wiki for Phoenix LiveView - please feel free to add any info you feel is worth including. What is Phoenix LiveV...
New
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
marick
I had some trouble figuring out how to make many-to-many associations work. Once I got it working, I wrote a blog post. Because I’m a nov...
New
openscript
Hello! Sorry for this astonishing simple question, but I’m really stuck. I try to set up the intellij-elixir plugin, but I don’t know ho...
New
PeterCarter
There are pre-rolled solutions for other frameworks that do work. However, Phoenix does not seem to have these. Have people had good expe...
New
dogweather
I wrote this comment on r/haskell, and it’s not popular there. :wink: But I think I’m on to something… Haskell reminds me of Java, and e...
New

We're in Beta

About us Mission Statement