Phoenix Elixir:模拟内部功能

时间:2017-09-25 17:43:56

标签: testing mocking elixir phoenix-framework ecto

我目前正在测试使用create_zone函数的控制器,该函数依赖于检索用户以将所述用户与区域相关联的函数,然后创建仅作为两个条目的关联表的参与者条目。

  def create_zone(attrs \\ %{}, user_id) do
    user = Accounts.get_user!(user_id)

    with{:ok, %Zone{} = zone} <- %Zone{}
    |> Zone.changeset(attrs,user)
    |> Repo.insert()
    do
    create_participant(zone,user)
   end
  end

我想用ExUnit测试它,但问题是测试框架试图搜索数据库中不存在的记录。

** (Ecto.NoResultsError) expected at least one result but got none in query:
   from u in Module.Accounts.User,
   where: u.id == ^1

我如何仅仅为了测试目的而模拟或创建它?

2 个答案:

答案 0 :(得分:1)

不要嘲笑它,用ex_machina创建它:https://github.com/thoughtbot/ex_machina

在Elixir中不鼓励嘲弄:http://blog.plataformatec.com.br/2015/10/mocks-and-explicit-contracts/(你现在真的不需要阅读它,但是如果你想要模拟一些外部资源,请阅读它。)

答案 1 :(得分:1)

您可以编写一个使用Ecto插入数据库的简单工厂模块。由于Ecto.Sandbox,测试将被包装在数据库事务中并自动回滚。

defmodule Factory do
  def create(User) do
    %User{
      name: "A. User",
      email: "user_#{:rand.uniform(10000)}@mail.com"
    }
  end

  def create(Zone) do
    %Zone{
       # ... random / default zone attributes here...
    }
  end

  def create(schema, attrs) do
    schema
    |> create()
    |> struct(attributes)
  end

  def insert(schema, attrs \\ []) do
    Repo.insert!(create(schema, attrs))
  end
end

然后在您的测试中,自定义属性与出厂默认值合并,包括关联。

test "A test" do
  user = Factory.insert(User, name: "User A")
  zone = Zones.create_zone(user.id)
  assert zone
end

有关更详细的解释,请参阅what's new in ecto 2.1的第7章。