micah

micah

Mox with Applications - to start or not to start

Hello all! I’m in the process of writing an application with a couple moving parts, but unit testing it is making me question everything.

My application supervises three processes:

children = [
        {DynamicSupervisor, strategy: :one_for_one, name: MyApp.SuperSpider},
        {MyApp.Database, name: MyApp.CurrentDatabase},
        {MyApp.SiteAPI, name: MyApp.SiteAPI},
 ]

When the SiteAPI starts, it loads and starts processes based on what is in the database:

def init(opts) do
     super_spider = opts |> Keyword.get(:super_spider, MyApp.SuperSpider)
     db = opts |> Keyword.get(:db, MyApp.CurrentDatabase)
     sites = db |> Database.get_sites()
     spiders = sites |> Enum.reduce(%{}, fn (site, acc) ->
       {:ok, new_pid} = DynamicSupervisor.start_child(
         super_spider, {MyApp.Spider, {site, db}}
       )
       Map.put(acc, site.id, new_pid)
     end)
     {:ok, %{db: db, super_spider: super_spider, spiders: spiders}}
end

Everything as near as I can tell works, except that when I start the unit tests using mix test, the application first uses the real “database” instead of the MockDatabase which is defined in test/test_helper.ex:

  Code.require_file("test/mock_dets.ex") # Mocking dets with ets
  Mox.defmock(MyApp.MockRequest, for: MyApp.Request)
  Mox.defmock(MyApp.MockDatabase, for: MyApp.Database)
  
  Application.put_env(:my_app, :use_delay, false)
  Application.put_env(:my_app, :request, MyApp.MockRequest)
  Application.put_env(:my_app, :database, MyApp.MockDatabase)
  Application.put_env(:my_app, :dets, MyApp.MockDETS)
 
  ExUnit.start()

When I run the unit tests, the Application is started before the Mox(s) are configured, and the real Database is used. What can I do to avoid this?

I’ve tried not starting the application with “–no-start” but this also stops the dependencies (like Mox) from starting.

Most Liked

micah

micah

@stefanchrobot Thank you for your quick response! MyApp.Database is both a behavior and a stub that routes it through the application environment variable “:database”

defmodule MyApp.Database do

  @doc """
    Create a new database process
  """
  @callback start_link() :: GenServer.on_start()
  def start_link(), do: impl().start_link()
  @callback start_link(_ :: integer) :: GenServer.on_start()
  def start_link(arg), do: impl().start_link(arg)

  @doc """
    Information for adding to supervision trees
  """
  @callback child_spec(term()) :: Supervisor.child_spec()
  def child_spec(arg), do: impl().child_spec(arg)

  # Lots more functions following a similar pattern here...

  defp impl, do: Application.get_env(:my_app, :database, MyApp.FileDB)
end

The whole app is open source, but it’s really messy (I’ve made some poor design/naming decisions) and definitely a work in progress: ~electric/shop_local: apps/product_search/lib/database.ex - sourcehut git

ajur58

ajur58

I had a very similar use-case to yours and almost gave up. Then I found your implementation linked above and it works!! Thanks for making it open source!

Where Next?

Popular in Questions Top

JDanielMartinez
Hi! May someone helps me, please! I have two apps into an umbrella project: the first one is Database, which manages queries, and the se...
New
shahryarjb
Hello, I get Persian date from my client and convert it to normal calendar like this: def jalali_string_to_miladi_english_number(persi...
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
sergio_101
I am VERY much an elixir newbie. I have taken one elixir course and one phoenix course on Udemy. During that course, I saw the instructor...
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
New
polypush135
As many of you may have realized by now (sorry for all the posts here) I’ve been working on a db problem where I’m trying to aggregate a ...
New
makeitrein
Hey all, just started picking up Elixir last week and am writing a scraper as a learning project. Baby step #1 is extracting the number ...
New
hpopp
To simplify some tasks at work, I wrote and published this package yesterday. It’s a simple macro that enables Access behaviour on struct...
New
Codball
Mix format works fine if run from the cmd. I’ve followed this to facilitate the implementation into VSC which involves downloading an ext...
New

Other popular topics Top

minhajuddin
I have seen a lot of code which picks the first element from a list using Enum.at(0) instead of List.first. Is there a reason why people ...
New
Harrisonl
We have an ECS cluster with 4 services, where each task joins a single cluster, via discovery ECS discovery service. Currently when I de...
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
hariharasudhan94
I would like to know what is the best IDE for elixir development?
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 49522 488
New
New
danschultzer
None of the current solutions worked well for me, so I went ahead and built a user management system from scratch. This project took far...
548 27727 240
New
aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
ashish173
I am using Ecto timestamps with postgres, I can see the timestamps() use the :naive_dateime but for my use case I wanted to store the ti...
New
qwerescape
Is there a way to get the call stack or stack trace at any point in the code? Not from exceptions, but an expression that returns how the...
New

We're in Beta

About us Mission Statement