Proper structuring of testable code in context

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

  1. should I split my function so that it does the checks and then calls the plain vanilla create function?
  2. should I test these two separately? and does it make sense to test each of them?
  3. do I need to rename the second one to insert_enrollment? because they have the same arguments, co calling create_enrollment in the first one would basically result in recursive call and infinite loop, right?

Thank you very much!