Hi, I have a function in context that reads value from other table before inserting a new record. Specifically, it checks class capacity before adding new enrollment into it.
See:
defmodule Enrol.Classes do
def create_enrollment(%{"class_id" => class_id} = attrs \\ %{}) do
# check if class capacity is not exhausted
# and inserts only then, otherwise rolls back
Repo.transaction(fn ->
capacity = Repo.one!(from c in Class, where: c.id == ^class_id, select: c.capacity)
count = Repo.one(from e in Enrollment, where: e.class_id == ^class_id, select: count(e.class_id))
case count < capacity do
true ->
# maybe call insert_enrollment(attrs) from here?
%Enrollment{}
|> Enrollment.changeset(attrs)
|> Repo.insert()
false ->
IO.puts "Class capacity EXCEEDED, rollback"
Repo.rollback(:class_full)
end
end) # end transaction
end
# default generic function
def create_enrollment(attrs \\ %{}) do
%Enrollment{}
|> Enrollment.changeset(attrs)
|> Repo.insert()
end
# alternative (just renamed)
def insert_enrollment(attrs \\ %{}) do
%Enrollment{}
|> Enrollment.changeset(attrs)
|> Repo.insert()
end
end
When writing unit tests for this context, this would mean creating a class fixture first, so that I can read its capacity, before testing insertion of the enrollment. I feel like the unit test should be more granular, and just check whether plain vanilla insertion works.
So my questions are
- should I split my function so that it does the checks and then calls the plain vanilla create function?
- should I test these two separately? and does it make sense to test each of them?
- do I need to rename the second one to
insert_enrollment? because they have the same arguments, co callingcreate_enrollmentin the first one would basically result in recursive call and infinite loop, right?
Thank you very much!


















