PianoFingers
PianoFingers

Reputation: 117

How to reference outside Contexts in test files?

I'm really struggling to understand Contexts in Phoenix Elixir. I have three contexts, Auth (contains User.ex), Groups (Circle.ex), and Content (ShareMark.ex). Within each of those, there are schemas, users, circles, and sharemarks respectively.

I'm trying to figure out how to use the pre-provided create_circle outside of the Groups context. Is there something a context is analogous to in Ruby?

Within content_test.ex, I am trying to define the following

@valid_attrs %{circle: Groups.create_circle(%{name: "My test"}), url: "google.com", title: "Google"}

defmodule ShareMark.ContentTest do
  use ShareMark.DataCase

  alias ShareMark.Content
  use ShareMark.Groups
  describe "sharemarks" do
    alias ShareMark.Content.ShareMark
    @valid_attrs %{circle: Groups.create_circle(%{name: "Evan's test"}), url: "google.com", title: "Google"}
    @update_attrs %{circle: Groups.create_circle(%{name: "Mike's test"}), url: "duckduckgo.com", title: "DuckDuckGo"}
    @invalid_attrs %{circle: Groups.create_circle(%{name: "Bad test"})}

    def sharemark_fixture(attrs \\ %{}) do
      {:ok, sharemark} =
        attrs
        |> Enum.into(@valid_attrs)
        |> Content.create_sharemark()

      sharemark
    end
 ...
end

Here is circle.ex

defmodule ShareMark.Groups.Circle do
  use Ecto.Schema
  import Ecto.Changeset

  schema "circles" do
    field :name, :string
    field :creator_id, :id
    many_to_many :members, ShareMark.Auth.User, join_through: "users_circles"
    has_many :sharemarks, ShareMark.Content.ShareMark

    timestamps()
  end

  @doc false
  def changeset(circle, attrs) do
    circle
    |> cast(attrs, [:name])
    |> validate_required([:name])
  end
end

But it is giving the following error:

** (CompileError) test/sharemark/content/content_test.exs:8: undefined function create_circle/1

Google is completely unhelpful, as Phoenix has so few questions asked about it. Sorry for such a novice question.

Upvotes: 0

Views: 141

Answers (2)

Sheharyar
Sheharyar

Reputation: 75820

For starters, does not force you to use Contexts, they're just a way of better organizing your code. This makes them slightly more confusing for beginners, compared to the File-Type First (FTF) structure of applications, but makes the code heirarchy much more easier to understand and manage in the long haul.

You can choose to use contexts or just put all modules together. Either way, whatever public functions you define are acessible from anywhere else in the app (as long as you use the correct module name to call them).

More resources on Contexts:


Now on to your actual code, there are two problems with it.

First, as @Paweł mentioned, you need to alias your module or use the full name:

alias ShareMark.Groups

Second, you're calling Groups.create_circle in a module attribute (@value). Module attributes aren't like your regular "variables", they are resolved at compile-time. Meaning, in your case, they will try to write to the database before you even start your test suite.

To fix that, either move your initialization logic to your actual test or into ExUnit's setup/1 callback:

setup do
  %{circle: Groups.create_circle(%{name: "Test Circle"}}
end

test "something", %{circle: circle} do
  valid_attrs = %{circle: circle, url: "google.com", title: "Google"}
  # assert something
end

Upvotes: 1

Paweł Dawczak
Paweł Dawczak

Reputation: 9649

In your test you have this line:

use ShareMark.Groups

this should be an alias statement:

alias ShareMark.Groups

Upvotes: 2

Related Questions