동호회 관리 플랫폼 개발기 #4 - Domain Rules
현재 Hoing 에는 3가지 리소스가 있다.
User
Club
Member
이 중 Club 리소스에 대한 도메인 규칙을 정하고, 이를 테스트로 표현해본다.
Club
Club 은 로그인 된 상태에서만 생성이 가능하다.
Club 을 생성한 생성자는 자동으로 Club 의 owner member 가 된다.
Club 의 owner 만 Club 정보를 수정할 수 있다.
generator
각 리소스의 생성자를 정의한다.
별도로 인자가 없는 경우 리소스를 생성하는데 필요한 다른 관계들은 자동으로 생성하도록 처리한다.
defmodule Hoing.Generator do
@moduledoc "Data generation for tests"
use Ash.Generator
def member(opts \\ []) do
user = opts[:user] || generate(user())
club = opts[:club] || generate(club())
seed_generator(
%Hoing.Clubs.Member{
user_id: user.id,
club_id: club.id,
role: :member
},
overrides: opts
)
end
def club(opts \\ []) do
actor = opts[:actor] || once(:default_user, fn -> generate(user()) end)
changeset_generator(
Hoing.Clubs.Club,
:create,
defaults: [
name: sequence(:club_name, &"Club #{&1}", &((&1 || 0) + 1)),
description: sequence(:club_description, &"Description of Club #{&1}")
],
overrides: opts,
actor: actor
)
end
def user(opts \\ []) do
seed_generator(
%Hoing.Accounts.User{
email: sequence(:user_email, &"user#{&1}@example.com")
},
overrides: opts
)
end
end
club_test.exs
위에서 정의한 generator 를 활용해서 테스트를 구현하자.
defmodule Hoing.Clubs.ClubTest do
use Hoing.DataCase, async: true
alias Hoing.Clubs, warn: false
describe "Hoing.Clubs.create_club!" do
test "can not create club without actor" do
assert_raise Ash.Error.Forbidden, fn ->
Clubs.create_club!(%{name: "New Club"})
end
end
test "can create club with actor" do
actor = generate(user())
club = Clubs.create_club!(%{name: "New Club"}, actor: actor)
assert club.name == "New Club"
end
test "set actor as owner member of the created club" do
actor = generate(user())
club = Clubs.create_club!(%{name: "New Club"}, actor: actor) |> Ash.load!(:members)
member = List.first(club.members)
assert length(club.members) == 1
assert member.user_id == actor.id
assert member.club_id == club.id
assert member.role == :owner
end
end
describe "Hoing.Clubs.update_club!" do
test "can not update club without actor" do
club = generate(club())
assert_raise Ash.Error.Forbidden, fn ->
Clubs.update_club!(club, %{name: "Updated Club"})
end
end
test "can update club if actor is owner of the club" do
user = generate(user())
club = generate(club(actor: user)) |> Ash.load!(:members)
member =
club.members
|> Enum.find(fn member -> member.user_id == user.id && member.club_id == club.id end)
updated_club =
Clubs.update_club!(club, %{name: "Updated Club", description: "No more description."},
actor: user,
context: %{member: member}
)
assert updated_club.id == club.id
assert updated_club.name == "Updated Club"
assert updated_club.description == "No more description."
end
test "can not update club if actor is not owner of the club" do
club = generate(club())
manager_user = generate(user())
manager_member = generate(member(user: manager_user, club: club, role: :manager))
member_user = generate(user())
member_member = generate(member(user: member_user, club: club, role: :member))
assert_raise Ash.Error.Forbidden,
fn ->
Clubs.update_club!(
club,
%{name: "Updated Club", description: "No more description."},
actor: manager_user,
context: %{member: manager_member}
)
end
assert_raise Ash.Error.Forbidden,
fn ->
Clubs.update_club!(
club,
%{name: "Updated Club", description: "No more description."},
actor: member_user,
context: %{member: member_member}
)
end
end
end
end
위 test 를 실행해보자.
mix test test/hoing/clubs/club_test.exs

test 가 정상작동하는 것을 확인할 수 있다.